Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: тестирование toolchain
Форум на CrossPlatform.RU > Разработка > Инструменты разработчика
igor_bogomolov
Кто нибудь знает какие-нибудь разумные фреймворки для тестирования тулчейнов?

Задача у меня следующая. Я собираю различные тулчейны для одной и той же arm архитектуры (отличаются версиями gcc и опциями конфигурирования пакетов).
Мне нужно знать какой из них лучше с точки зрения производительности. Интересует скорость работы с памятью, скорость работы математических библиотек, в особенности с точкой (т.к. процессор без fpu), скорость работы с текстом, с потоками и т.д.

У кого есть опыт в этом деле?

igor_bogomolov
Нашел несколько небольших примеров: libc-bench, strbench (это из того что хоть как то понравилось). Хочу собрать их в одно целое, привести вывод к общему виду, добавить недостающие части. Одна из недостающих частей - это тесты libm. Нацарапал быстренько такой тест, хочется услышать от других на сколько он адекватный?

Раскрывающийся текст
#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/wait.h>

#define PI 3.14159265

void print_stats(const char *name, struct timespec tv0)
{
    FILE *f;
    char buf[256];
    struct timespec tv;
    int maj, min, in_heap=0;
    unsigned long l;
    size_t vm_size=0, vm_rss=0, vm_priv_dirty=0;

    clock_gettime(CLOCK_REALTIME, &tv);
    tv.tv_sec -= tv0.tv_sec;
    if ((tv.tv_nsec -= tv0.tv_nsec) < 0) {
        tv.tv_nsec += 1000000000;
        tv.tv_sec--;
    }

    f = fopen("/proc/self/smaps", "rb");
    if (f) while (fgets(buf, sizeof buf, f)) {
        if (sscanf(buf, "%*lx-%*lx %*s %*lx %x:%x %*lu %*s", &maj, &min)==2)
            in_heap = (!maj && !min && !strstr(buf, "---p") && (strstr(buf, "[heap]") || !strchr(buf, '[')));
        if (in_heap) {
            if (sscanf(buf, "Size: %lu", &l)==1) vm_size += l;
            else if (sscanf(buf, "Rss: %lu", &l)==1) vm_rss += l;
            else if (sscanf(buf, "Private_Dirty: %lu", &l)==1) vm_priv_dirty += l;
        }
    }
    if (f) fclose(f);
    printf(": %-15s : %ld.%.9ld   : %-6zu   : %-6zu   : %-6zu   :\n",
        name, (long)tv.tv_sec, (long)tv.tv_nsec,
        vm_size, vm_rss, vm_priv_dirty);
}

void run_bench(const char *name, double (*bench)(double), double param)
{
    int k;
    volatile double result;
    struct timespec tv0;
    pid_t p = fork();                                                                                                                                                                                                
    if (p) {
        int status;
        wait(&status);
        return;
    }

    clock_gettime(CLOCK_REALTIME, &tv0);
    for (k = 0; k < 1000000; ++k) {
        result = bench(param);
        assert(!result || result);
    }
    print_stats(name, tv0);
    exit(0);
}

void run_benchf(const char *name, float (*benchf)(float), float param)
{
    int k;
    volatile float result;
    struct timespec tv0;
    pid_t p = fork();
    if (p) {                                                                                                                                                                                                    
        int status;
        wait(&status);
        return;
    }

    clock_gettime(CLOCK_REALTIME, &tv0);
    for (k = 0; k < 1000000; ++k) {
        result = benchf(param);
        assert(!result || result);
    }
    print_stats(name ,tv0);
    exit(0);
}

int main (int argc, char *argv[])
{
    printf ("--------------------------------------------------------------------\n");
    printf (":                   Trigonometric functions                        :\n");
    printf ("--------------------------------------------------------------------\n");
    printf (": Name            : Time          : Virt     : Res      : Dirty    :\n");
    printf ("--------------------------------------------------------------------\n");

    run_bench ("sin",  sin,  30.0*PI/180);
    run_benchf("sinf", sinf, 30.0*PI/180);
    run_bench ("cos",  cos,  60.0*PI/180);
    run_benchf("cosf", cosf, 60.0*PI/180);
    run_bench ("tan",  tan,  45.0*PI/180);
    run_benchf("tanf", tanf, 45.0*PI/180);

    run_bench ("asin",  asin,  0.5);
    run_benchf("asinf", asinf, 0.5);
    run_bench ("acos",  acos,  0.5);
    run_benchf("acosf", acosf, 0.5);
    run_bench ("atan",  atan,  1.0);
    run_benchf("atanf", atanf, 1.0);

    printf ("--------------------------------------------------------------------\n");
    printf (":                   Hyperbolic functions                           :\n");
    printf ("--------------------------------------------------------------------\n");

    run_bench ("sinh",  sinh,  0.69314718056);
    run_benchf("sinhf", sinhf, 0.69314718056);
    run_bench ("cosh",  cosh,  0.69314718056);
    run_benchf("coshf", coshf, 0.69314718056);
    run_bench ("tanh",  tanh,  0.69314718056);
    run_benchf("tanhf", tanhf, 0.69314718056);

    run_bench ("asinh",  asinh,  0.75);
    run_benchf("asinhf", asinhf, 0.75);
    run_bench ("acosh",  acosh,  1.25);
    run_benchf("acoshf", acoshf, 1.25);
    run_bench ("atanh",  atanh,  0.60);
    run_benchf("atanhf", atanhf, 0.60);

    printf ("--------------------------------------------------------------------\n");
    printf (":                   Exponential and logarithmic functions          :\n");
    printf ("--------------------------------------------------------------------\n");

    run_bench ("exp",    exp,    5.0);
    run_benchf("expf",   expf,   5.0);
    run_bench ("exp1m",  expm1,  5.0);
    run_benchf("exp1mf", expm1f, 5.0);

    run_bench ("log",    log,    5.5);
    run_benchf("logf",   logf,   5.5);
    run_bench ("log10",  log10,  1000.0);
    run_benchf("log10f", log10f, 1000.0);
    run_bench ("log1p",  log1p,  0.05);
    run_benchf("log1pf", log1pf, 0.05);

    printf ("--------------------------------------------------------------------\n");
    printf (":                   Power functions                                :\n");
    printf ("--------------------------------------------------------------------\n");

    run_bench ("sqrt",  sqrt,   1024.0);
    run_benchf("sqrtf", sqrtf,  1024.0);
    run_bench ("cbrt",  cbrt,  32768.0);
    run_benchf("cbrtf", cbrtf, 32768.0);

    printf ("--------------------------------------------------------------------\n\n");

    return 0;
}

Iron Bug
у тебя функция print_stats немногопоточная. будет бардак при выводе на экран.
BRE
Цитата(Iron Bug @ 22.9.2011, 21:39) *
у тебя функция print_stats немногопоточная. будет бардак при выводе на экран.

Почему? Там все линейно. :)
igor_bogomolov
Цитата(Iron Bug @ 22.9.2011, 21:39) *
у тебя функция print_stats немногопоточная. будет бардак при выводе на экран.
В этом варианте родительский процесс дожидается завершения порожденного процесса, только после этого продолжает свое выполнение.
Но на самом деле вы правы. Я от этого варианта уже отказался, убрал fork и вывод информации из /proc/self/smaps.
В приведенном выше варианте есть немного другой неприятный эффект. Если запускать приложение из консоли просто так, мы видим нормальный вывод. А вот если перенаправить поток в файл, начинается полная ерунда. Все что я вывел в поток ввода/вывода из родительского процесса, дублируется в дочернем.

P.S. Трудно на самом деле объяснить суть, попробуйте просто скомпилировать этот пример и поэкспериментировать немного.
Iron Bug
Цитата(BRE @ 22.9.2011, 23:43) *
Почему? Там все линейно. :)

fork копирует ПРОЦЕСС. а процесс тут один и он не завершается при выходе из процедуры. он завершается при завершении main. и поэтому будет много-много раз выведено всё из main и вообще полный бардак.

по идее, чтобы это работало так, как задумано, нужно порождать отдельные процессы для run_bench и run_benchf.
BRE
Цитата(Iron Bug @ 23.9.2011, 0:14) *
fork копирует ПРОЦЕСС. а процесс тут один и он не завершается при выходе из процедуры. он завершается при завершении main. и поэтому будет много-много раз выведено всё из main и вообще полный бардак.

Ты заблуждаешься. Почитай про fork. ;)
igor_bogomolov
BRE, в чем именно заблуждение? Все происходит именно так, как написала Iron Bug.
Iron Bug
Цитата(BRE @ 23.9.2011, 2:19) *
Ты заблуждаешься. Почитай про fork.

fork() creates a child process that differs from the parent process only in its PID and PPID.
классика жанра, однако. я это ещё на первом курсе универа читала :)
процесс в данном случае - один. ВСЯ его память, включая сегменты кода и данных и стек, копируется. с чего ради я ошибаюсь? именно так и будет: выходов из main будет столько, сколько вызовов fork плюс один.

например, потестируем:
Раскрывающийся текст

#include <sys/wait.h>
#include <iostream>

using namespace std;

void dummy()
{
    pid_t p = fork();
    if (p) {
        int status;
        wait(&status);
        return;
    }
}

int main()
{
    for(int i=0;i<3;i++)
    {
        dummy();
    }
    cout << "exit!" << endl;
    return 0;
}



:D
а теперь догадайтесь, думая логически, сколько надписей "exit!" будет на экране?
копируется ВСЁ. включая циклы.
BRE
Цитата(igor_bogomolov @ 23.9.2011, 0:29) *
BRE, в чем именно заблуждение? Все происходит именно так, как написала Iron Bug.

Давайте смотреть код. :)
void run_bench(const char *name, double (*bench)(double), double param)
{
    ...
    pid_t p = fork();                                                                                                                                                                                                
    if (p) {
        int status;            // После форка сюда попадает parent-процесс
        wait(&status);        // Он ждет завершение child-процесса. После wait дочернего потока уже не существует!!!
        return;            // Пока child не завершиться parent процесс стоит, т.е. следующий тест запуститься только после завершения предыдущего!!!
    }

    // Сюда, после форка, попадет child-процесс.
    // Здесь он работает
    // ...
    // И завершается
    exit(0);
}


В каждый момент времени существует либо parent-процесс, либо parent-процесс и ОДИН child-процесс!
igor_bogomolov
Цитата(BRE @ 23.9.2011, 0:38) *
В каждый момент времени существует либо parent процесс, либо parent процесс и ОДИН child-процесс!
Ну это понятно.
Вопрос в том, как при этом ведут себя потоки ввода/вывода. Я же не отвязываю порожденные процессы от них. Поэтому все что писалось в поток из родительского процесса дублируется существующим дочерним.
Iron Bug
Цитата(BRE @ 23.9.2011, 2:38) *
В каждый момент времени существует либо parent-процесс, либо parent-процесс и ОДИН child-процесс!

если насчёт нереентерабельности, то я просто return не заметила. но бардака это не отменяет и fork делает именно то, что я написала выше.
BRE
Цитата(igor_bogomolov @ 23.9.2011, 0:47) *
Вопрос в том, как при этом ведут себя потоки ввода/вывода. Я же не отвязываю порожденные процессы от них. Поэтому все что писалось в поток из родительского процесса дублируется существующим дочерним.

Согласен. Перед форком буферу вывода стоит делать flush. :)
Тогда не будет такого эффекта при перенаправлении в файл.


Цитата(Iron Bug @ 23.9.2011, 0:52) *
но бардака это не отменяет и fork делает именно то, что я написала выше.

Так в чем тогда бардак? Каждый тест выполняется последовательно в своем процессе.
igor_bogomolov
Цитата(BRE @ 23.9.2011, 0:58) *
Согласен. Перед форком буферу вывода стоит делать flush.
flush в стандартном СИ нет, а на момент написания кода fflush(stdout) сделать не догадался. Завтра на работе проверю, просто что бы убедиться. А так я уже писал, что переделал тесты и теперь все выполняется в одном процессе и в одном потоке.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Форум IP.Board © 2001-2024 IPS, Inc.