Yazılım Geliştirme: C ++ 17'de tahsisatçılarla optimizasyon

Adanali

Active member
Yazılım Geliştirme: C ++ 17'de tahsisatçılarla optimizasyon


  1. Yazılım Geliştirme: C ++ 17'de tahsisatçılarla optimizasyon

Polimorfik, C ++ 17'de tahsis eder, hafızanın hem performans hem de belleğin yeniden kullanılması üzerine atanmasını optimize etmeye yardımcı olur.










Rainer Grimm yıllardır yazılım mimarı, ekip ve eğitim müdürü olarak çalıştı. C ++ programlama dilleri, Python ve Haskell hakkında makaleler yazmayı seviyor, ancak uzman konferanslarla konuşmayı da seviyor. Modern C ++ blogunda, C ++ tutkusuyla yoğun bir şekilde ilgileniyor.







performans


Aşağıdaki program cppreference.com/monotonic_buffer_resource adresinden geliyor. Klan performansı ve MSVC derleyicisi için performansını genişleteceğim ve açıklayacağım.



// pmrPerformance.cpp
// https://en.cppreference.com/w/cpp/memory/monotonic_buffer_resource

#include <array>
#include <chrono>
#include <cstddef>
#include <iomanip>
#include <iostream>
#include <list>
#include <memory_resource>

template<typename Func>
auto benchmark(Func test_func, int iterations) // (1)
{
const auto start = std::chrono::system_clock::now();
while (iterations-- > 0)
test_func();
const auto stop = std::chrono::system_clock::now();
const auto secs = std::chrono::duration<double>(stop - start);
return secs.count();
}

int main()
{
constexpr int iterations{100};
constexpr int total_nodes{2'00'000};

auto default_std_alloc = [total_nodes] // (2)
{
std::list<int> list;
for (int i{}; i != total_nodes; ++i)
list.push_back(i);
};

auto default_pmr_alloc = [total_nodes] // (3)
{
std::pmr::list<int> list;
for (int i{}; i != total_nodes; ++i)
list.push_back(i);
};

auto pmr_alloc_no_buf = [total_nodes] // (4)
{
std::pmr::monotonic_buffer_resource mbr;
std::pmr::polymorphic_allocator<int> pa{&mbr};
std::pmr::list<int> list{pa};
for (int i{}; i != total_nodes; ++i)
list.push_back(i);
};

auto pmr_alloc_and_buf = [total_nodes] // (5)
{
// enough to fit in all nodes:
std::array<std::byte, total_nodes * 32> buffer;
std::pmr::monotonic_buffer_resource mbr{buffer.data(),
buffer.size()};
std::pmr::polymorphic_allocator<int> pa{&mbr};
std::pmr::list<int> list{pa};
for (int i{}; i != total_nodes; ++i)
list.push_back(i);
};

const double t1 = benchmark(default_std_alloc, iterations);
const double t2 = benchmark(default_pmr_alloc, iterations);
const double t3 = benchmark(pmr_alloc_no_buf , iterations);
const double t4 = benchmark(pmr_alloc_and_buf, iterations);

std::cout << std::fixed << std::setprecision(3)
<< "t1 (default std alloc): " << t1
<< " sec; t1/t1: " << t1/t1 << 'n'
<< "t2 (default pmr alloc): " << t2
<< " sec; t1/t2: " << t1/t2 << 'n'
<< "t3 (pmr alloc no buf): " << t3
<< " sec; t1/t3: " << t1/t3 << 'n'
<< "t4 (pmr alloc and buf): " << t4
<< " sec; t1/t4: " << t1/t4 << 'n';
}


(1) 'deki bu performans testi, (2) – (5)' deki işlevleri yüz kez yönlendirir (constexpr int iterations{100}). Her işlev çağrısı bir tane yaratır std::pmr::list<int> İki yüz bin düğüm ile (constexpr int total_nodes{2'00'000}). Bireysel listelerin düğümleri farklı şekillerde atanır:

  • (2): std::list<int> Küresel kullanma operator new
  • (3): std::pmr::list<int> Özel Depolama Kaynağını Kullanın std::pmr::new_delete_resource
  • (4): std::pmr::list<int> kullanılmış std::pmr::monotonic_buffer Daha önce yığın üzerine atanmış bir arabellek olmadan
  • (5): std::pmr::list kullanılmış std::pmr::monotonic_buffer Daha önce yığın üzerine atanmış bir arabellek ile
Son işlev (5) hakkındaki yorum, yığın üzerinde tüm düğümleri barındırmak için yeterli alan olduğunu söylüyor: “Tüm düğümlere uyum sağlayacak kadar“Bu benim Linux PC'mde, ancak Windows PC'imde değil. Linux altında 8 MB yığın için standart boyut, ancak Windows altında sadece 1 Mbyte. Bu, MSVC derleyicisi ve klan derleyicisi ile Windows altında program yürütmemin sonucuna sahipti. editbin.exe Yürütülebilir MSVC ve klanımın yığınının boyutu değişti:











İşte sayılar. Referans değeri, std::list<int> (Riga 2). Mutlak, ancak göreceli sayıları karşılaştırın, çünkü sanallaştırılmış bir Linux PC ve virtual olmayan bir Windows PC kullandım. Açıkçası maksimum optimizasyonu etkinleştirdim. Bu şu anlama gelir (/Ox) MSVC derleyicisi için ve (-Ox) GCC ve Clang derleyicisi için.




















Depolama kaynağı ile bellek atamasının std::pmr::new_delete_resource En yavaş. Aksine std::pmr::monotonic_buffer Hafızanın en hızlı atanması. Bu, daha önce yığın üzerine atanmış bir arabellek kullanırsanız doğrudur. Windows'a bellek tahsisi yaklaşık on kat daha hızlıdır.






C ++ 20 ile tanıtılan kavramlar, modern C ++ uygulamalarının oluşturulmasını kütüphane, modüller ve aralıkların aralıkları ile yeniden tanımladı. 7 – 9 Kasım arasında 2023'te Rainer Grimm sizi yoğun C ++ 20 laboratuvarına getirdi: Yeni kavramlar tamamen açıkladı ve C ++ 20 Porta'nın birçok yararlı işlevine yanıt verdi.







Depolama kaynağı std::pmr::new_delete_resource Daha da fazla optimizasyon sunar.

Hafızanın yeniden kullanılması


std::pmr::monotonic_buffer Depolama sürümünü kaydedebilmeniz için belleğin yeniden kullanılmasını sağlar.



// reuseMemory.cpp

#include <array>
#include <cstddef>
#include <iostream>
#include <memory_resource>
#include <string>
#include <vector>

int main() {

std::array<std::byte, 2000> buf;

for (int i = 0; i < 100; ++i) { // (1)
std::pmr::monotonic_buffer_resource pool{buf.data(),
buf.size(), // (2)
std::pmr::null_memory_resource()};
std::pmr::vector<std::pmr::string> myVec{&pool};
for (int j = 0; j < 16; ++j) { // (3)
myVec.emplace_back("A short string");
}
}
}


Bu Alca Programı std::array 2000 bayt ile: std::array<std::byte, 2000>. Yığın tarafından atanan bu bellek yüz kez yeniden kullanılır (1). . std::pmr::vector<std::prm::string> Kullanın std::pmr::monotonic_buffer_resource Yukarı akış depolama kaynağı ile std::pmr::null_memory_resource (2). Son olarak, taşıyıcıya 16 ip itilir.

Sırada ne var?


Bu makale C ++ 17'deki polimorfik depolama kaynakları hakkındaki mini serimi sona erdiriyor. Bir sonraki makalemde üç yıl boyunca atlamaya devam edeceğim ve C ++ 20 üzerinden yolculuğuma devam edeceğim.


(RME)
 
Üst