DTO'ları optimize etme

Bu sayfada DTO uygulamanızda yapabileceğiniz optimizasyonlar anlatılır, kök düğümün yer paylaşımına karşı kısıtlamalar açıklanır ve DTBO görüntüsünde sıkıştırılmış yer paylaşımlarının nasıl yapılandırılacağı ayrıntılarıyla anlatılır. Ayrıca örnek uygulama talimatları ve kodu da sağlar.

Çekirdek komut satırı

Aygıt ağacındaki orijinal çekirdek komut satırı chosen/bootargs düğümünde bulunur. Önyükleyicinin bu konumu diğer çekirdek komut satırı kaynaklarıyla birleştirmesi gerekir:

/dts-v1/;

/ {
  chosen: chosen {
    bootargs = "...";
  };
};

DTO, ana CE'den ve yer paylaşımlı CE'den gelen değerleri birleştiremez , bu nedenle ana CE'nin çekirdek komut satırını chosen/bootargs ve yer paylaşımlı CE'nin çekirdek komut satırını chosen/bootargs_ext içine koymalısınız. Bootloader daha sonra bu konumları birleştirebilir ve sonucu çekirdeğe aktarabilir.

ana.dts kaplama.dts
/dts-v1/;

/ {
  chosen: chosen {
    bootargs = "...";
  };
};
/dts-v1/;
/plugin/;

&chosen {
  bootargs_ext = "...";
};

özgürlük

En son libfdt DTO'yu desteklerken, DTO'yu uygulamak için libufdt kullanılması önerilir ( platform/system/libufdt adresindeki AOSP kaynağı). libufdt düzleştirilmiş aygıt ağacından (FDT) gerçek bir ağaç yapısı (düzleştirilmemiş aygıt ağacı veya ufdt ) oluşturur, böylece iki .dtb dosyasının O(N 2 )'den O(N)'ye (burada N) birleştirilmesini iyileştirebilir. ağaçtaki düğümlerin sayısıdır.

Performans testi

Google'ın dahili testinde, 2405 .dtb ve 283 .dtbo DT düğümlerinde libufdt kullanılması, derleme sonrasında 70.618 ve 8.566 baytlık dosya boyutlarıyla sonuçlanır. FreeBSD'den (124 ms çalışma süresi) taşınan bir DTO uygulamasıyla karşılaştırıldığında, libufdt DTO çalışma süresi 10 ms'dir.

Pixel cihazları için performans testleri libufdt ve libfdt karşılaştırdı. Temel düğüm sayısı etkisi benzerdir ancak aşağıdaki farklılıkları içerir:

  • 500 katmanlama (ekleme veya geçersiz kılma) işleminde 6 ila 8 kat zaman farkı vardır
  • 1000 katmanlama (ekleme veya geçersiz kılma) işleminde 8 ila 10 kat zaman farkı vardır

Ekleme sayısının X olarak ayarlandığı örnek:

Şekil 1. Eklenen sayı X'tir

Geçersiz kılma sayısının X olarak ayarlandığı örnek:

Şekil 2. Geçersiz kılma sayısı X'tir

libufdt bazı libfdt API'leri ve veri yapılarıyla geliştirilmiştir. libufdt kullanırken, libfdt eklemeniz ve bağlamanız gerekir (ancak kodunuzda DTB veya DTBO'yu çalıştırmak için libfdt API'sini kullanabilirsiniz).

libufdt DTO API'si

libufdt DTO'ya yönelik ana API aşağıdaki gibidir:

struct fdt_header *ufdt_apply_overlay(
        struct fdt_header *main_fdt_header,
        size_t main_fdt_size,
        void *overlay_fdt,
        size_t overlay_size);

main_fdt_header parametresi ana CE'dir ve overlay_fdt bir .dtbo dosyasının içeriğini içeren arabellektir. Dönüş değeri, birleştirilmiş CE'yi içeren yeni bir arabellektir (veya hata durumunda null ). Birleştirilmiş DT, çekirdeği başlatırken çekirdeğe iletebileceğiniz FDT'de biçimlendirilir.

Dönüş değerinden gelen yeni arabellek, libufdt önyükleyiciye taşırken uygulamanız gereken dto_malloc() tarafından oluşturulur. Referans uygulamaları için sysdeps/libufdt_sysdeps_*.c dosyasına bakın.

Kök düğüm kısıtlamaları

Yer paylaşımı işlemleri etiketlere bağlı olduğundan, ana CE'nin kök düğümüne yeni bir düğümü veya özelliği yerleştiremezsiniz. Ana DT'nin bir etiket tanımlaması gerektiğinden ve kaplama DT'si, etiketlerle kaplanacak düğümlere atadığından, kök düğüm için bir etiket veremezsiniz (ve dolayısıyla kök düğümü kaplayamazsınız).

SoC satıcıları ana DT'nin üst üste bindirme yeteneğini tanımlamalıdır; ODM/OEM'ler yalnızca SoC satıcısı tarafından tanımlanan etiketlere sahip düğümleri ekleyebilir veya geçersiz kılabilir. Geçici bir çözüm olarak, temel DT'deki kök düğümün altında bir odm düğümü tanımlayarak, kaplama DT'deki tüm ODM düğümlerinin yeni düğümler eklemesini sağlayabilirsiniz. Alternatif olarak, temel DT'deki tüm SoC ile ilgili düğümleri aşağıda açıklandığı gibi kök düğüm altındaki bir soc düğümüne yerleştirebilirsiniz:

ana.dts kaplama.dts
/dts-v1/;

/ {
    compatible = "corp,bar";
    ...

    chosen: chosen {
        bootargs = "...";
    };

    /* nodes for all soc nodes */
    soc {
        ...
        soc_device@0: soc_device@0 {
            compatible = "corp,bar";
            ...
        };
        ...
    };

    odm: odm {
        /* reserved for overlay by odm */
    };
};
/dts-v1/;
/plugin/;

/ {
};

&chosen {
    bootargs_ex = "...";
};

&odm {
    odm_device@0 {
        ...
    };
    ...
};

Sıkıştırılmış kaplamaları kullanma

Android 9, cihaz ağacı tablosu başlığının 1. sürümünü kullanırken DTBO görüntüsünde sıkıştırılmış kaplamaların kullanılmasına yönelik destek ekler. DTBO başlığı v1 kullanıldığında, dt_table_entry'deki flags alanının en az anlamlı dört biti, DT girişinin sıkıştırma formatını belirtir.

struct dt_table_entry_v1 {
  uint32_t dt_size;
  uint32_t dt_offset;  /* offset from head of dt_table_header */
  uint32_t id;         /* optional, must be zero if unused */
  uint32_t rev;        /* optional, must be zero if unused */
  uint32_t flags;      /* For version 1 of dt_table_header, the 4 least significant bits
                        of 'flags' will be used to indicate the compression
                        format of the DT entry as per the enum 'dt_compression_info' */
  uint32_t custom[3];  /* optional, must be zero if unused */
};

Şu anda zlib ve gzip sıkıştırmaları desteklenmektedir.

enum dt_compression_info {
    NO_COMPRESSION,
    ZLIB_COMPRESSION,
    GZIP_COMPRESSION
};

Android 9, katman uygulamasının doğruluğunu doğrulamanıza yardımcı olmak için VtsFirmwareDtboVerification testine sıkıştırılmış katmanları test etme desteği ekler.

Örnek DTO uygulaması

Aşağıdaki talimatlar, libufdt ile DTO'nun örnek uygulaması konusunda size yol gösterecektir (örnek kod aşağıdadır).

Örnek DTO talimatları

  1. Kitaplıkları dahil edin. libufdt kullanmak için veri yapıları ve API'ler için libfdt ekleyin:
    #include <libfdt.h>
    #include <ufdt_overlay.h>
    
  2. Ana CE'yi ve bindirme CE'yi yükleyin. .dtb ve .dtbo depolamadan belleğe yükleyin (tam adımlar tasarımınıza bağlıdır). Bu noktada .dtb / .dtbo tamponuna ve boyutuna sahip olmalısınız:
    main_size = my_load_main_dtb(main_buf, main_buf_size)
    
    overlay_size = my_load_overlay_dtb(overlay_buf, overlay_buf_size);
    
  3. CE'leri kaplayın:
    1. Ana DT'nin FDT başlığını almak için ufdt_install_blob() işlevini kullanın:
      main_fdt_header = ufdt_install_blob(main_buf, main_size);
      main_fdt_size = main_size;
      
    2. FDT formatında birleştirilmiş bir DT almak için DTO'ya ufdt_apply_overlay() işlevini çağırın:
      merged_fdt = ufdt_apply_overlay(main_fdt_header, main_fdt_size,
                                      overlay_buf, overlay_size);
      
    3. dtc_totalsize() boyutunu elde etmek için merged_fdt kullanın:
      merged_fdt_size = dtc_totalsize(merged_fdt);
      
    4. Çekirdeği başlatmak için birleştirilmiş CE'yi iletin:
      my_kernel_entry(0, machine_type, merged_fdt);
      

Örnek DTO kodu

#include <libfdt.h>
#include <ufdt_overlay.h>

…

{
  struct fdt_header *main_fdt_header;
  struct fdt_header *merged_fdt;

  /* load main dtb into memory and get the size */
  main_size = my_load_main_dtb(main_buf, main_buf_size);

  /* load overlay dtb into memory and get the size */
  overlay_size = my_load_overlay_dtb(overlay_buf, overlay_buf_size);

  /* overlay */
  main_fdt_header = ufdt_install_blob(main_buf, main_size);
  main_fdt_size = main_size;
  merged_fdt = ufdt_apply_overlay(main_fdt_header, main_fdt_size,
                                  overlay_buf, overlay_size);
  merged_fdt_size = dtc_totalsize(merged_fdt);

  /* pass to kernel */
  my_kernel_entry(0, machine_type, merged_fdt);
}