Информация об изменениях

Сообщение Re: [performance] чего-то я не понимаю в этой жизни от 05.07.2022 14:13

Изменено 05.07.2022 15:08 σ

Re: [performance] чего-то я не понимаю в этой жизни
В общем, погонял в ленсуке:
$ dotnet --version
6.0.301
$ g++ --version
g++ (Ubuntu 11.2.0-19ubuntu1) 11.2.0

  C#
using System.Diagnostics;

var vals = new string[0x4000_000];
var random = new Random(DateTime.Now.Second);

var watch = Stopwatch.StartNew();
for (var i = 0; i < vals.Length; i++)
    vals[i] = random.Next().ToString();
watch.Stop();

Console.WriteLine($"Init: {watch.Elapsed.TotalSeconds}");

TestPerformanceManaged(vals);

static void TestPerformanceManaged(string[] vals)
{
    var watch = Stopwatch.StartNew();

    var res = 0;
    foreach (var val in vals)
        res ^=  ParseInt(val);

    Console.WriteLine("Hash = {0:X}", res);

    watch.Stop();
    Console.WriteLine($"TestPerformanceManaged: {watch.Elapsed.TotalSeconds}");
}

static int ParseInt(string val)
{
    int res = 0;
    foreach (var d in val)
    {
        if ('0' <= d && d <= '9')
            res = res * 10 + d - '0';
        else
            throw new ArgumentOutOfRangeException("'" + d + "': Symbol is out of the range");
    }
    return res;
}
  C++
#include <iostream>
#include <vector>
#include <string>
#include <chrono>
#include <random>


std::vector<std::wstring> MakeIntSequence(int size)
{
   std::mt19937 gen(std::random_device{}());
   std::uniform_int_distribution<> distrib(0, std::numeric_limits<int>::max());
   std::vector<std::wstring> v;
   v.reserve(size);

   for (int i = 0; i < size; ++i)
      v.push_back(std::to_wstring(distrib(gen)));

   return v;
}

int ParseInt(const std::wstring& wstr)
{
   int res{};

   for (auto d : wstr)
   {
      if ('0' <= d && d <= '9')
         res = res * 10 + d - '0';
      else
         throw std::out_of_range("'" + std::to_string(d) + "': Symbol is out of range");
   }

   return res;
}

int main()
{
   namespace tm = std::chrono;

   const auto vals = MakeIntSequence(0x4000000);

   const auto t0 = tm::steady_clock::now();

   int hash{};
   for (const auto& val : vals)
      hash ^= ParseInt(val);
   const auto dt = tm::duration_cast<tm::milliseconds>(tm::steady_clock::now() - t0);

   std::cout << "Hash = " << std::hex << hash << std::endl;
   std::cout << "Processing time: " << std::dec << dt.count() << "ms" << std::endl;
}
Флаги g++: `-std=c++17 -O2`. Флаги C# — ХЗ, запускал так: `dotnet run --configuration Release`.

Цепепе: 698, 704 и 715ms.
Сисярп: 0.7095647, 0.729915 и 0.7312779

UPD
  u16string
#include <chrono>
#include <codecvt>
#include <iostream>
#include <locale>
#include <random>
#include <string>
#include <vector>


std::u16string to_u16string(int i)
{
    std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> conv;
    return conv.from_bytes(std::to_string(i));
}

std::vector<std::u16string> MakeIntSequence(int size)
{
    std::mt19937 gen(std::random_device{}());
    std::uniform_int_distribution<> distrib(0, std::numeric_limits<int>::max());
    std::vector<std::u16string> v;
    v.reserve(size);

    for (int i = 0; i < size; ++i)
        v.push_back(to_u16string(distrib(gen)));

    return v;
}

int ParseInt(const std::u16string& wstr)
{
    int res{};

    for (auto d : wstr)
    {
        if ('0' <= d && d <= '9')
            res = res * 10 + d - '0';
        else
            throw std::out_of_range("'" + std::to_string(d) + "': Symbol is out of range");
    }

    return res;
}

int main()
{
    namespace tm = std::chrono;

    const auto vals = MakeIntSequence(0x4000000);

    const auto t0 = tm::steady_clock::now();

    int hash{};
    for (const auto& val : vals)
        hash ^= ParseInt(val);
    const auto dt = tm::duration_cast<tm::milliseconds>(tm::steady_clock::now() - t0);

    std::cout << "Hash = " << std::hex << hash << std::endl;
    std::cout << "Processing time: " << std::dec << dt.count() << "ms" << std::endl;
}
763, 772, 775ms и жрёт кучу памяти, больше, чем с 4-хбайтовым wstring. Думаю, из-за конверсий.
Re: [performance] чего-то я не понимаю в этой жизни
В общем, погонял в ленсуке:
$ dotnet --version
6.0.301
$ g++ --version
g++ (Ubuntu 11.2.0-19ubuntu1) 11.2.0

  C#
using System.Diagnostics;

var vals = new string[0x4000_000];
var random = new Random(DateTime.Now.Second);

var watch = Stopwatch.StartNew();
for (var i = 0; i < vals.Length; i++)
    vals[i] = random.Next().ToString();
watch.Stop();

Console.WriteLine($"Init: {watch.Elapsed.TotalSeconds}");

TestPerformanceManaged(vals);

static void TestPerformanceManaged(string[] vals)
{
    var watch = Stopwatch.StartNew();

    var res = 0;
    foreach (var val in vals)
        res ^=  ParseInt(val);

    Console.WriteLine("Hash = {0:X}", res);

    watch.Stop();
    Console.WriteLine($"TestPerformanceManaged: {watch.Elapsed.TotalSeconds}");
}

static int ParseInt(string val)
{
    int res = 0;
    foreach (var d in val)
    {
        if ('0' <= d && d <= '9')
            res = res * 10 + d - '0';
        else
            throw new ArgumentOutOfRangeException("'" + d + "': Symbol is out of the range");
    }
    return res;
}
  C++
#include <iostream>
#include <vector>
#include <string>
#include <chrono>
#include <random>


std::vector<std::wstring> MakeIntSequence(int size)
{
   std::mt19937 gen(std::random_device{}());
   std::uniform_int_distribution<> distrib(0, std::numeric_limits<int>::max());
   std::vector<std::wstring> v;
   v.reserve(size);

   for (int i = 0; i < size; ++i)
      v.push_back(std::to_wstring(distrib(gen)));

   return v;
}

int ParseInt(const std::wstring& wstr)
{
   int res{};

   for (auto d : wstr)
   {
      if ('0' <= d && d <= '9')
         res = res * 10 + d - '0';
      else
         throw std::out_of_range("'" + std::to_string(d) + "': Symbol is out of range");
   }

   return res;
}

int main()
{
   namespace tm = std::chrono;

   const auto vals = MakeIntSequence(0x4000000);

   const auto t0 = tm::steady_clock::now();

   int hash{};
   for (const auto& val : vals)
      hash ^= ParseInt(val);
   const auto dt = tm::duration_cast<tm::milliseconds>(tm::steady_clock::now() - t0);

   std::cout << "Hash = " << std::hex << hash << std::endl;
   std::cout << "Processing time: " << std::dec << dt.count() << "ms" << std::endl;
}
Флаги g++: `-std=c++17 -O2`. Флаги C# — ХЗ, запускал так: `dotnet run --configuration Release`.

Цепепе: 698, 704 и 715ms.
Сисярп: 0.7095647, 0.729915 и 0.7312779

std::string: ~690-695ms.

UPD
  u16string
#include <chrono>
#include <codecvt>
#include <iostream>
#include <locale>
#include <random>
#include <string>
#include <vector>


std::u16string to_u16string(int i)
{
    std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> conv;
    return conv.from_bytes(std::to_string(i));
}

std::vector<std::u16string> MakeIntSequence(int size)
{
    std::mt19937 gen(std::random_device{}());
    std::uniform_int_distribution<> distrib(0, std::numeric_limits<int>::max());
    std::vector<std::u16string> v;
    v.reserve(size);

    for (int i = 0; i < size; ++i)
        v.push_back(to_u16string(distrib(gen)));

    return v;
}

int ParseInt(const std::u16string& wstr)
{
    int res{};

    for (auto d : wstr)
    {
        if ('0' <= d && d <= '9')
            res = res * 10 + d - '0';
        else
            throw std::out_of_range("'" + std::to_string(d) + "': Symbol is out of range");
    }

    return res;
}

int main()
{
    namespace tm = std::chrono;

    const auto vals = MakeIntSequence(0x4000000);

    const auto t0 = tm::steady_clock::now();

    int hash{};
    for (const auto& val : vals)
        hash ^= ParseInt(val);
    const auto dt = tm::duration_cast<tm::milliseconds>(tm::steady_clock::now() - t0);

    std::cout << "Hash = " << std::hex << hash << std::endl;
    std::cout << "Processing time: " << std::dec << dt.count() << "ms" << std::endl;
}
763, 772, 775ms и жрёт кучу памяти, больше, чем с 4-хбайтовым wstring. Думаю, из-за конверсий.