воскресенье, 10 марта 2013 г.

Простейшая работа со временем в языке Си

Допустим нам необходимо получить строку выводящую время на "человеческом" языке. Как исходный шаблон можем использовать следующую функцию:
void
timestamp ( void )
{
    static char time_buffer[100];
    const struct tm *tm;
    size_t len;
    time_t now;

    now = time ( NULL );
    tm = localtime ( &now );
    len = strftime ( time_buffer, 100, "%d %B %Y %I:%M:%S %p", tm );
    printf ( "%s\n", time_buffer );

    return;
}

Пусть теперь нам надо посмотреть, как много времени забирает выполнение того или иного участка кода. Для решения этой задачи будет удобным следующий пример:
#include<stdio.h>
#include
<stdlib.h>
#include<time.h>

Расширения языка Си в CUDA

Имеется четыре типа расширений языка Си в CUDA. Это:
  1. Квалификаторы типа функции, определяющие, где эта функция будет выполняться - в центральном процессоре или на видеокарте, и возможно ли вызывать эту функцию из центрального процессора или видеокарты.
  2. Квалификаторы типа переменных, определяющие распределение памяти для этих переменных на видеокарте.
  3. Директива, определяющая как ядро выполняется на видеокарте.
  4. Четыре встроенных переменных, определяющих размерность грида, размерность блока, индекс блока и индекс нити.
Рассмотрим эти расширения подробней.
I.Квалификаторы типа функций
  1. __device__ квалификатор говорит, что функция выполняется на видеокарте и может быть вызвана только из видеокарты.
  2. __global__ квалификатор объявляет функцию выполняемой в  центральном процессоре и вызываемой только процессором. Квалифицирование функции только __host__ аналогично объявлению функции без какого-то ни было квалификатора. Однако функцию можно квалифицировать комбинацией __host__ __device__. Тогда функция будет откомпилирована и для центрального процессора и для видеокарты.  
 Ограничения:
  •  функции квалифицированные __device__ и __global__ не поддерживают рекурсии.
  •  функции квалифицированные __device__ и __global__ не могут декларировать внутри себя статические переменные.
  • функции квалифицированные __device__ и __global__ не могут иметь переменное количество аргументов.
  • функции квалифицированные __device__ не могут вызываться по их адресу.
  • функции не могут быть одновременно квалифицированы как __global__ и __host__.
  • функции квалифицированные как __global__ обязаны возвращать пустой тип.
  • функции квалифицированные как __global__ должны специфицировать  свою конфигурацию выполнения.
  • функции квалифицированные как __global__ выполняются синхронно.
  • параметры функций квалифицированных как __global__ передаются через общую память в видеокарту и ограничены 256-ю байтами.
II. Квалификаторы переменных.
  1. __device__ квалификатор говорит, что переменная размещается на видеокарте. Может использоваться совместно с другими квалификаторами типа переменных. Если таковых нет, то это означает, что переменная размещена в глобальной памяти, имеет время жизни равное времени жизни приложения и доступна из нитей в гриде и с центрального процессора через библиотеку времени исполнения.
  2. __constant__ квалификатор опционально используемый предыдущим квалификатором объявляет, что переменная размещается в области постоянной памяти, имеет время жизни равное времени жизни приложения и доступна из нитей в гриде и с центрального процессора через библиотеку времени исполнения.
  3. __shared__ квалификатор опционально используемый с  __device__ квалификатором объявляет, что перменная размещается в общей памяти блока нитей, имеет время жизни равное времени жизни блока и доступна только из нитей данного блока.
Ограничения:
  • Эти квалификаторы не допустимы для членов struct и union, в формальных параметрах функций и локальныхперменных внутри функций, что выполняются на центральном процессоре.
  • __shared__ и __shared__ не могут использоваться вместе.
  • __shared__ и __shared__ переменные подразумеваются статическими.
  • __constant__ переменные не могут использоваться внутри видеокарты, только на центральном процессоре. Поэтому они имеют область видимости файла.
  • __shared__ переменные не могут иметь инициализацию как часть их декларации.
III. Конфигурация выполнения.
Любой вызов функции __global__ должен специфицировать конфигурацию выполнения этой функции. Конфигурация выполнения функции определяет размерность грида и блоков, которые будут использоваться при вызове функции на видеокарте. Эта конфигурация задается аргументами между тройными угловыми скобками. <<>>. Эта конструкция помещается между именем функци и списком передаваемым в функцию списком "обычных" аргументов.
Описание аргументов в угловых скобках следующее:
  1. Dg - имеет тип dim3 и определяет размерность и длину грида так что выражение Dg.x*Dg.y равно числу запущенных блоков.
  2. Db - имеет тип dim3 и определяет размерность и длину каждого блока, так что выражение Db.x*Db.y*Db.z равно числу нитей в каждом блоке.
  3. Ns - имеет тип size_t и определяет количество байтов в общей памяти, которая выделяется динамически при данном вызове функции дополнительно к ее статической памяти. Ns - необязательный аргумент со значением по умолчанию раным нулю.
Аргументы конфигурации выполнения вычисляются раньше  "обычных" аргументов функции.
IV. Встроенные переменные
  1. gridDim - переменная типа dim3. Содержит размерность грида.
  2. blockIdx - переменная типа uint3. Содержит индекс блока в гриде.
  3. blockDim - переменная типа dim3. Содержит размерность блока.
  4. threadIdx - переменная типа uint3. Содержит индекс нити в блоке.
Ограничения:
  • не допустима операция получения адреса от любой встроенной переменной.
  • не допустима операция присваивания для любой встроенной переменной.

суббота, 26 января 2013 г.

Cовместное использование языков Си и Фортран.

В UNIX системах языки Си и Фортран могут использоваться вместе, так как между этими языками возможны прямые вызовы функций. При этом, правда, необходимо тщательно учитывать совместимость типов передаваемых аргументов. Обычно соответствие между типами в Си и Фортране можно представить так:
signed char    INTEGER*1
short               INTEGER*2
int                   INTEGER
long                INTEGER*4
float                REAL
double            DOUBLE PRECISION
void sub_        SUBROUTINE SUB()
float  fun_()     REAL FUNCTION FUN
Также следует помнить о следующем: 
  • в Фортране аргументы в функции всегда передаются ссылками;
  • В Си массивы передаются через адрес;
  • Порядок индексации многомерных массивов различен для Си и Фортрана - в Си элементы массива располагаются построчно, в Фортране - по столбцам;
  • Имена функций в Фортране имеют в своем конце "скрытый" знак подчеркивания '_' (его нет в исходном тексте, но он добавляется компилятором), поэтому, если некая фунция вызывается из Фортрана как fun(), то эта же функция из Си вызывается как fun_() ; 
  • В языке Си длина строки определяется положением нулевого байта, в Фортране же строки имеют фиксированную длину. Поэтому при передаче строки из Си кода в Фортран необходимо передавать также ее длину. В случае же передачи строки из Фортран кода в Си необходимо добавить нуль в конец строки;
Рассмотрим два случая: когда си код вызывается из фортрана и , наоборот, когда из фортран кода вызывается си код.
Файл cCode1.c:
#include<stdio.h>
void
c_function_(){
     printf("Hello from C code!\n");
}
 Файл fortranCode1.f90:
program hello
    implicit none
    call c_function()
    write (*,*)"Hello from FORTRAN code!"
end program hello
 Компилируем и запускаем на выполнение:
#gfortran -O2 -g -o fortranCode1.o -c fortranCode1.f90
#gcc -O2 -g -o cCode1.o -c cCode1.c
#gcc -L /usr/lib/gcc/i486-linux-gnu/4.7/ -lgfortran fortranCode1.o cCode1.o -o hello1
#./hello1
Нужно, чтобы присутствовала библиотека libgfortran.so
 /usr/lib/gcc/i486-linux-gnu/4.7/ - это путь, по которомуона у меня лежит. У вас может быть другой путь.
Обратный случай:
Файл cCode2.c:
#include<stdio.h>
void
main(){
     fortran_function_();
     printf("Hello from C code!\n");
Файл fortranCode2.f90:
subroutine fortran_function
    implicit none
    write (*,*)"Hello from FORTRAN code!"
end subroutine fortran_function
Компилируем и запускаем на выполнение:
#gfortran -O2 -g -o fortranCode2.o -c fortranCode2.f90
#gcc -O2 -g -o cCode2.o -c cCode2.c
#gcc -L /usr/lib/gcc/i486-linux-gnu/4.7/ -lgfortran fortranCode2.o cCode2.o -o hello2
#./hello2
Теперь сделаем вызов функции с передачей параметров разных типов.
Файл cCode3.c:
#include<stdio.h>
void
c_function_(signed char* a1, short* a2, int* a3, long int* a4){
     printf("in called c function: \n%d\t%d\t%d\t%ld\n", *a1, *a2, *a3, *a4);
}
 Файл fortranCode3.f90:
program hello
    implicit none
    integer*1 a1
    integer*2 a2
    integer*4 a3
    integer*8 a4
    a1=1
    a2=22
    a3=333
    a4=4444
    call c_function(a1, a2, a3, a4)
end program hello
 #gfortran -O2 -g -o fortranCode3.o -c fortranCode3.f90
#gcc -O2 -g -o cCode3.o -c cCode3.c
#gcc -L /usr/lib/gcc/i486-linux-gnu/4.7/ -lgfortran fortranCode3.o cCode3.o -o hello3
#./hello3
 Файл cCode4.c:
#include<stdio.h>
void
main(){
     signed char a1 = 1;
     short            a2 = 22;
     int                 a3 = 333;
     long              a4 = 4444;
     fortran_function_(&a1, &a2, &a3, &a4);
Файл fortranCode4.f90:
subroutine fortran_function(f1, f2, f3, f4)
    implicit none
    integer*1 f1
    integer*2 f2
    integer*4 f3
    integer*4 f4
    write (*,100)f1,f2,f3,f4
100 format(4i5)
end subroutine fortran_function
#gfortran -O2 -g -o fortranCode4.o -c fortranCode4.f90
#gcc -O2 -g -o cCode4.o -c cCode4.c
#gcc -L /usr/lib/gcc/i486-linux-gnu/4.7/ -lgfortran fortranCode4.o cCode4.o -o hello4
#./hello4
Теперь продемонстрируем передачу символьных строк из Си в Фортран и обратно.

Файл cCode5.c:
#include<stdio.h>
void
     c_function_(char* string){
     printf("%s\n", string);
}
 Файл fortranCode5.f90:
program hello
    implicit none
    character*37 string
    string="Created in fortran, outputed from C!"
    string(37:37)=char(0)
    call c_function(string)
end program hello
#gfortran -O2 -g -o fortranCode5.o -c fortranCode5.f90
#gcc -O2 -g -o cCode5.o -c cCode5.c
#gcc -L /usr/lib/gcc/i486-linux-gnu/4.7/ -lgfortran fortranCode5.o cCode5.o -o hello5
#./hello5 
Теперь наоборот. Сформируем строку в Си, а напечатаем в Фортране.
Файл cCode6.c:
#include<string.h>
void
main(){
     char string[37];
     int length = sizeof(string);
     strncpy(string, "Created in C, outputed from Fortran!", length);
     fortran_function_(string, &length);
}
Файл fortranCode6.f90:
subroutine fortran_function(string, length)
    implicit none
    character*(*) string
    integer length
    write(*,100)string(1:length)
100 format(a)
    return
end subroutine fortran_function
#gfortran -O2 -g -o fortranCode6.o -c fortranCode6.f90
#gcc -O2 -g -o cCode6.o -c cCode6.c
#gcc -L /usr/lib/gcc/i486-linux-gnu/4.7/ -lgfortran fortranCode6.o cCode6.o -o hello6
#./hello6
Все примеры протестированы в Debian Wheezy.

среда, 16 января 2013 г.

sed: убираем лишнее

При работе с большими текстовыми файлами, хранящими данные для построения графиков, очень часто не нужен весь объем хранимой  информации. Тут на помощь может прийти утилита sed.
Чтобы удалить каждую 5-ю, например, строку, можно сделать так: 
sed -n '0~5d' bigdata.txt > lessdata.txt
А что если мы хотим не удалить каждую 5-ю, а сохранить, удалив остальные строки? Тогда так:
sed -n '0~5p' bigdata.txt > lessdata.txt
Следующая команда делает то же плюс сохраняет первую и последнюю строки:
sed -n '1p;0~5p;$p' bigdata.txt > lessdata.txt 

среда, 9 января 2013 г.

Gnuplot: линейная аппроксимация

Пусть у нас имеется текстовый файл myData.dat состоящий из двух колонок цифр и мы хотим нарисовать два графика: первый, изображенный символами (точками), собственно данные; второй, представленный линией, которая и является линейной аппроксимацией этих данных. Создадим файл myApproximation.plt следующего содержания:
my_linear_fit(x)=a*x+b
fit my_linear_fit(x) 'myData.dat' via a,b
plot 'myData.dat'     title 'my data', my_linear_fit(x) title 'approximation of my data' 
И запустим gnuplot из директории, в которой создали этот файл и введем команду:
>load 'myApproximation.plt'
Для задания диапазонов абсциссы и ординаты пользуем такие команды:
>set xrange [0:100]
>set yrange[0:]
Цифры даны для примера.