Перейти к тексту

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

При первом входе в developerWorks для Вас будет создан профиль. Выберите информацию отображаемую в Вашем профиле — скрыть или отобразить поля можно в любой момент.

Вся введенная информация защищена.

  • Закрыть [x]

При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

Вся введенная информация защищена.

  • Закрыть [x]

Изменения в libspe: как использование libspe2 изменяет программирование для Cell Broadband Engine

Научитесь управлять и взаимодействовать с SPE-процессом при помощи libspe2

Джонатан Бартлетт, технический директор, New Media Worx
Джонатан Бартлет (Jonathan Bartlett) является автором книги "Программирование с нуля" - введения в программирование на языке ассемблера для Linux. Он является ведущим разработчиком в New Media Worx и занимается Web-приложениями (видео, киосками), а также настольными приложениями для клиентов. Вы можете связаться с ним по адресу johnnyb@eskimo.com.

Описание:  Стандартная библиотека libspe, которую программы Power Processor Element используют для доступа и управления Synergistic Processor Elements (SPE), подвергнута значительной модификации. Cell Broadband Engine™ (Cell/B.E.) SDK 2.1 официально меняет интерфейс библиотеки с libspe1 на libspe2. В этой статье Джонатан Бартлет описывает концепцию libspe2 и показывает, как управлять и взаимодействовать с SPE-процессом при помощи libspe2.

Дата:  22.11.2007
Уровень сложности:  средний
Активность:  1573 просмотров
Комментарии:  


libspe предоставляет программистам интерфейс для управления и взаимодействия с SPE-процессом. Переход с libspe1 на libspe2 влечет за собой полное переосмысление способов, которыми SPE-процессы управляются из PPE. В этой статье я ссылаюсь на основную библиотеку безотносительно номера версии, как на libspe, и буду использовать libspe1 и libspe2 для ссылок на конкретную версию.

Перед погружением в libspe2 вы должны обратить внимание на то, что целью libspe не является управление физическими SPE. Поскольку коды, которые использует libspe, представляют собой коды пользовательского уровня, она не имеет возможности прямой модификации аппаратных ресурсов. Коды пользовательского уровня запрашивают ресурсы SPE у операционной системы, которая выполняет это физически таким способом, который операционная система полагает лучшим. Например, операционной системе разрешается назначать множественные контексты на единственный физический SPE путем загрузки и выгрузки контекстов по мере необходимости. Каждый SPE-процесс будет получать доступ ко всему SPE до тех пор, пока он выполняется, но операционная система может свободно приостановить выполнение в любом месте (чтобы возобновить его позже) и назначить для выполнения другой SPE-контекст. Все это будет невидимым для пользовательского программного обеспечения как на SPE, так и на PPE, за исключением того, что чрезмерные переключения контекстов на SPE будут приводить к снижению производительности.

В libspe1 ресурс SPE, управляемый операционной системой, называется потоком (thread); в libspe2 этот ресурс называется контекстом (context). Это не просто терминологическое изменение — напротив, цель libspe2 состоит в том, чтобы отделить модель организации поточной обработки от управления ресурсами SPE.

Создание и использование контекстов SPE

Два основных различия между libspe1 и libspe2 состоят в выполнении кода SPE. В libspe1 создание и выполнение контекста осуществляется одновременно при помощи spe_create_thread. В libspe2 это два отдельных шага (как вы увидите ниже, в действительности это несколько шагов).

В libspe1 вызовы для запуска SPE-кода обрабатываются асинхронно. spe_create_thread заставляет выполняться код SPE одновременно с продолжающим выполняться кодом PPE. В libspe2 вызовы для запуска кода SPE управляются синхронно. Это означает, что для того, чтобы получить один или несколько одновременно обрабатываемых SPE-потоков, программа должна создать эти потоки в коде PPE, а затем выполнять программу SPE в каждом из этих потоков. Может показаться, что объем работы увеличивается, но на самом деле достаточно просто спрятать этот код во вспомогательные функции, и способ выполнения программы SPE станет более гибким.

Это программа libspe1, которая запускает выполнение нового SPE-потока (введите как ppe_example.c):


Листинг 1. Простой пример создания libspe1 потока
                
#include <stdlib.h>
#include <stdio.h>
#include <libspe.h>

/* Предполагается, что у вас есть встроенная SPE-программа под именем test_handle  */
extern spe_program_handle_t test_handle; 

int main() {
	/* Создаем поток и записывам его ID */
	speid_t spe_id = spe_create_thread(0, &test_handle, NULL, NULL, -1, 0);
	int status;

	/* Проверяем ошибки */
	if(spe_id == 0) {
		perror("Unable to create SPE thread");
		exit(1);
	}

	/* Ждем завершения */
	spe_wait(spe_id, &status, 0);

	return 0;
}

Это SPE-код для этой программы (введите как spe_example.c):


Листинг 2. SPE-код для демонстрации потока
                
#include <stdio.h>
int main(unsigned long long spe_id, unsigned long long pdata) {
       printf("Hello world!\n"); /* Обратный вызов в PPE */ 

        return 0;
}  

Чтобы создать программу, просто введите:

spu-gcc spe_example.c -o spe_example
ppu-embedspu test_handle spe_example spe_example_csf.o
ppu-gcc ppe_example.c spe_example_csf.o -lspe -o ppe_example

PPE-часть этой программы может быть переписана с использованием libspe2 следующим образом (SPE-код остается без изменений):


Листинг 3. Простой пример создания libspe2 потока
                
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <libspe2.h>

/* ОБРАТИТЕ ВНИМАНИЕ — прототип основан на стандартной сигнатуре потоков pthread */
void *spe_test_function(void *data);

/* Предполагается, что у вас есть встроенная SPE-программа под именем test_handle */
extern spe_program_handle_t test_handle;

int main() {
	pthread_t my_thread;
	int retval;
	
	/* Создать поток */
	retval = pthread_create(
		&my_thread, /* Указатель на объект потока  */
		NULL, /* Свойства потока */
		spe_test_function, /* Функция потока */
		NULL /* Аргумент потока */
	);

	/* Проверка ошибок при создании потока */
	if(retval) {
		fprintf(stderr, "Error creating thread! Exit code is: %d\n", retval);
		exit(1);
	}

	/* Ждем завершения потока */
	retval = pthread_join(my_thread, NULL);
	/* Проверка ошибок в объединении потоков */
	if(retval) {
		fprintf(stderr, "Error joining thread! Exit code is: %d\n", retval);
		exit(1);
	}

	return 0;
}

/* ОБРАТИТЕ ВНИМАНИЕ — прототип основан на стандартной сигнатуре потоков pthread */
void *spe_test_function(void *data) {
	int retval;
	unsigned int entry_point = SPE_DEFAULT_ENTRY; 
	/* Необходимо для продолжения выполнения,
	SPE_DEFAULT_ENTRY представляет собой стандартное начальное смещение. */
	spe_context_ptr_t my_context;

	/* Создать SPE-контекст  */
	my_context = spe_context_create(SPE_EVENTS_ENABLE|SPE_MAP_PS, NULL);

	/* Загрузить в этот контекст встроенный код */
	spe_program_load(my_context, &test_handle);

	/* Выполнять SPE-программу, пока она не завершится */
	do {
		retval = spe_context_run(my_context, &entry_point, 0, NULL, NULL, NULL);
	} while (retval > 0); /* Выполнять до завершения или ошибки */

	pthread_exit(NULL);
}

Процесс сборки этой программы мало отличается:

spu-gcc spe_example.c -o spe_example
ppu-embedspu test_handle spe_example spe_example_csf.o
ppu-gcc ppe_example.c spe_example_csf.o -lspe2 -o ppe_example

Как вы можете видеть, libspe2 использует pthread для управления поточной обработкой, а не полагается на то, что это сделает для вас libspe (чтобы больше узнать о pthread, смотрите раздел Ресурсы в конце статьи). Процедура, которой следует код, такова:

  • Создать и запустить pthread (pthread_create).
  • Создать SPE-контекст (spe_context_create).
  • Загрузить SPE-код в контекст (spe_program_load).
  • Выполнять SPE-код до завершения (spe_context_run).

Разбиение процесса на этапы дает программисту возможность прямого контроля каждого этапа процесса. Хотите использовать другую потоковую модель? Просто замените вызовы pthread любой другой системой организации поточной обработки по вашему выбору. Хотите выполнять не встроенные в приложение, а внешние исполняемые файлы? Просто используйте spe_image_open перед вызовом spe_program_load. Хотите настроить работу обратных вызовов PPE? Просто настройте цикл и флаги для spe_context_run. Все это слишком сложно? Просто заключите последовательность, которая работает у вас лучше всего, во вспомогательную функцию.

Весь процесс весьма прямолинеен, за исключением spe_context_run. Это функция, которая в действительности выполняет код на SPE. Это синхронное выполнение, означающее, что пока выполняется SPE-код, выполнение обрабатывающегося в данный момент потока на PPE приостанавливается. Когда SPE-код завершается или временно приостанавливается (например, для передачи сигналов), PPE-поток возобновляет работу. В простой программе, показанной здесь, вы просто выходите из цикла do..while, содержащего spe_context_run. Однако в более сложных программах можно сохранить и проверить возвращаемое значение, чтобы определить, является оно нормальным выходом из программы или результатом вызова управляющих команд stop и signal, и требует специальной обработки.

spe_context_run также имеет некоторые интересные аргументы. Первый аргумент — это просто ссылка на контекст, который вы хотите выполнять. Второй же аргумент — это указатель на смещение в программе, которую вы хотите выполнить. Действительно, вы буквально указываете SPE, с какого байта программы вы хотите начать выполнение. Такой способ легче, чем может показаться. Прежде всего, точкой старта для всех программ по умолчанию является SPE_DEFAULT_ENTRY. Во-вторых, поскольку вы передаете указатель на величину, функция spe_context_run модифицирует величину при возвращении, так что она указывает на правильную позицию повторного входа. Поэтому, если она правильно инициализирована, точка входа будет поддерживаться с помощью самой функции spe_context_run. Это дает вам дополнительную гибкость в возможности повторного запуска SPE-программы после сигналов с любого места по вашему желанию.

Третий аргумент представляет собой набор флагов. Обычно достаточно установить их равными нулю. Вы также можете установить флаг SPE_NO_CALLBACKS, который означает, что ваша программа будет обрабатывать все функции обратного вызова, а не позволять функции spe_context_run обрабатывать их и скрывать их от вас. Четвертый и пятый аргументы — это argp и envp. Они используются при запуске SPE-программы для передачи аргументов и переменных окружения SPE-программе (эти параметры такие же, как и в spe_create_thread в libspe1). И наконец, последний аргумент — это необязательный указатель на структуру типа spe_stop_info_t. Она дает вам детальную информацию о причинах возврата spe_context_run. Однако для большинства приложений достаточно информации, содержащейся в коде возврата функции.

Код возврата для spe_context_run — 0 при успешном окончании программы, положительное число показывает, что были выполнены команды "stop и signal" (фактическое значение будет величиной, установленной сигнальными командами), а -1 указывает на ошибку (в таком случае будет установлено errno, а детальная информация, если она предусмотрена, будет в структуре spe_stop_info_t).

Функции обратного вызова PPE

В libspe1 SPE-программы могут легко вызывать некоторые функции libc на PPE и поэтому по существу имеют доступ к libc операционной системы. Однако список функций, которые может использовать SPE, был по существу предопределен. libspe2 обеспечивает интерфейс для включения дополнительных PPE-функций обратного вызова, которые доступны для вызова из SPE.

Чтобы создать дополнительные функции обратного вызова на PPE, вы должны создать как саму функцию в вашем PPE, так и сформировать заглушку на SPE, которая осуществит переход. При осуществлении обратных вызовов SPE передает PPE указатель на единственный четырех-байтовый аргумент и не обеспечивает непосредственной поддержки возвращаемой величины. Обычный способ действия при вызове и возврате из обратного вызова состоит в создании структуры для хранения как параметров функции, так и возвращаемой величины. Адрес этой структуры будет передаваться в качестве данных. Помните, что функция обратного вызова не получает в этом случае указателя, а получает указатель на указатель.

Прототип функции обратного вызова:

int the_callback_function(void *ls_base, unsigned int data_ptr);

Возвращаемая величина при успехе — 0, а любая другая величина считается ошибкой, которая будет вызывать завершение spe_context_run (сама возвращаемая величина будет в структуре spe_stop_info_t, если это предусмотрено). ls_base представляет собой эффективный адрес памяти (виртуальный адрес PPE-процесса), куда было отображено локальное хранилище SPE. data_ptr — это SPE-указатель на параметр, который передается из SPE. Поскольку адресное пространство SPE было отображено в памяти адресного пространства PPE, очень просто перемещать данные в локальную память SPE и из нее.

Поскольку data_ptr — это SPE-указатель, его нужно обсудить отдельно. Вспомним, что SPE-указатели ссылаются на адресное пространство локальной памяти, а не на адресное пространство PPE-процессов. Это означает, что все SPE-указатели должны быть транслированы в адресное пространство PPE до разыменования. Чтобы сделать это, необходимо:

  1. Иметь ls_base как char *, чтобы арифметические операции на нем трактовали его как байты.
  2. Сложить SPE-указатель с ls_base.
  3. Привести результат к указателю соответствующего типа.
  4. Назначить или разыменовать новый указатель.

Для указателей на указатели (подобных data_ptr) процедура будет немного более сложной, так как вы должны выполнить только что указанную процедуру для каждой стадии разыменования.

Использование вместо DMA отраженного в памяти локального хранилища облегчает доступ аргументов к обратным вызовам (которые находятся в локальном хранилище SPE). Доступ к локальному хранилищу SPE через отраженный в памяти интерфейс может быть медленным, потому что он идет через MMIO вместо DMA. Однако это не является проблемой для сохранения и извлечения данных небольшого объема, в отличие от сохранения больших объемов данных. Такой подход имеет два преимущества, которые особенно полезны для выполнения обратных вызовов:

  • Для передачи данных, отображенных в памяти, не нужно сохранять 16-байтовые выравнивания данных, как это необходимо для DMA-передач.
  • Передачу данных, отображенных в памяти, гораздо проще выполнять, так как это просто короткое преобразование адресного пространства, за которым следует разыменование указателей, а не инициирование DMA-передачи и ожидание ее окончания.

В любом случае у вас будет обращение к локальному хранилищу через адреса, отображенные в памяти, и вы можете свободно выполнять их, используя любой способ по вашему желанию.

В качестве примера я реализую функцию обратного вызова, которая вычисляет длину строки. На самом деле это излишне, поскольку функция strlen() уже реализована в SPE libc, но это хороший пример, так как он имеет возвращаемое значение, простые аргументы и простую реализацию. Ниже показано, как будет выглядеть PPE-функция:


Листинг 4. Пример PPE-функции обратного вызова
                
/* Мы используем данное определение, чтобы было более очевидно, какими величинами
являются SPE-адреса (которые мы трактуем как смещения от ls_base) */
typedef unsigned int spe_offset_t; 

/* Это наша структура ввода/вывода */
typedef struct {
	spe_offset_t str; /* Входной параметр — это адрес в SPE */
	int length; /* Результат */
} my_strlen_param_t;

int my_strlen(void *ls_base_tmp, unsigned int data_offset) {
	/* Преобразуем void-указатель в char-указатель — это позволит нам осуществлять
	байтовые сдвиги внутри отображенного в памяти адресного пространства */
	char *ls_base = (char *)ls_base_tmp; 

	/* Помещаем PPE-указатель в переменную указатель  "params" */
	/* Мы посылаем &params в эту функцию, но data_offset в действительности имеет 
	значение &(&params)  */
	spe_offset_t params_offset = *((spe_offset_t *)(ls_base + data));

	/* Теперь используем это для поиска значения &params */
	my_strlen_param_t *params = (my_strlen_param_t *)(ls_base + params_offset);

	/* Преобразуем SPE-адрес строки в адрес PPE */
	char *the_string = ls_base + params->str;

	/* Вычисляет длину строки и возвращает ее  */
	params->length = strlen(the_string);

	/* Успешное окончание */
	return 0;
}

Теперь, когда реальный код написан, мне еще нужно написать заглушку для SPE, чтобы запустить эту функцию. В соответствии со спецификацией libspe2, SPE необходимо иметь следующую последовательность инструкций на языке ассемблера, чтобы использовать обратные вызовы:

stop 0x2110    #стоп сообщает SPE, чтобы он прекратил выполнение, просигналил PPE 
	       #и  передал значение "0x2110"
	       #21" в "0x2110" сообщает PPE, что вы запрашиваете обратный вызов
	       #"10" в "0x2110" сообщает PPE, какой обратный вызов вы запрашиваете

actual_data:
.word 0        #Это "данные", которые будут переданы вашей программе. Мы добавляем метку
	       #actual_data, так что значения могут быть загружены сюда 
	       #до подачи сигнала PPE  


#Здесь продолжается выполнение. Механизм обратного вызова 
#пропускает "данные" при возвращении.

Вы могли заметить, что код ссылается на мой PPE-код при помощи числа 0x2110. Шестнадцатеричные цифры 21 сообщают сигнальному механизму, что это обратный PPE-вызов, а шестнадцатеричные цифры 10 ссылаются на конкретный обратный вызов, который я пытаюсь вызвать. Со стороны PPE каждый обратный вызов должен быть зарегистрирован системой обратного вызова на определенном номере между 0x00 и 0xff. От 0 до 3 зарезервировано для функций C99, POSIX и Linux® (здесь используется вторичный «код операции», указывающий на конкретную функцию в байтах высшего порядка). Функции обратного вызова могут быть зарегистрированы с использованием spe_callback_handler_register. Первый параметр — это адрес функции, второй параметр — номер обратного вызова для регистрации, и последний параметр должен быть SPE_CALLBACK_NEW. Заметьте, что эта конкретная особенность несколько дефектна, поскольку возникает ошибка, если номер уже используется. Поэтому, если ваш обратный вызов не вызывается, попробуйте переместить его на другой номер.

Не беспокойтесь, вам не понадобится писать команды на языке ассемблера, для этого существует прекрасная функция на C. Чтобы сделать вызов из С, нужно использовать функцию __send_to_ppe из библиотеки С. Она выполняет магические команды на языке ассемблера, необходимые для того, чтобы остановить SPE, просигналить PPE и передать единственный аргумент. __send_to_ppe вызывается с тремя аргументами:

  • Первый аргумент — это сигнал, который посылается PPE. Обратные вызовы PPE начинаются с шестнадцатеричных цифр 21 и два следующие шестнадцатеричные числа указывают на номер того обратного вызова, который будет вызван.
  • Второй аргумент используется для обратных вызовов, которые обозначают наборы функций и служат, в основном, для того, чтобы разрешить функциям обратного вызова изменять функциональность, основываясь на значении этого параметра. Эта величина обычно вставляется в старшие байты указателя данных. Самое простое — использовать 0 для этого аргумента.
  • Третий аргумент представляет собой данные (обычно указатель), которые надо передать в PPE. Помните, что старшие байты третьего параметра будут заменены величиной второго параметра, когда система реально передает аргументы.

__send_to_ppe существенно облегчает создание заглушек. В примере с длиной строки заглушка SPE выглядит следующим образом:

#include <sys/send_to_ppe.h>

/* Мы могли бы использовать указатель, но выполнение таким способом делает это 
согласованно в SPE и PPE */
typedef unsigned int spe_offset_t; 

/* Это наша структура ввода/вывода */
typedef struct {
	spe_offset_t str; /* Входной параметр — это адрес в SPE */
	int length; /* Результат */
} my_strlen_param_t;

int my_strlen(char *str) {
	/* Устанавливаем параметры */
	my_strlen_param_t params = { (spe_offset_t)str, 0 };

	/* Сигналим PPE (возвратимся, когда  PPE закончит работу) */
	__send_to_ppe(0x2110, 0, &params);

	/* Возвращаем результат */
	return params.length;
}

Ниже представлен полный листинг программы, которая использует обратные вызовы. Сначала код PPE (введите как callback_ppe.c):


Листинг 5. Код PPE, иллюстрирующий функции обратного вызова
                
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <libspe2.h>
#include <string.h>

/* Определяем типы */
typedef unsigned int spe_offset_t;
typedef struct {
	spe_offset_t str;
	int length;
} my_strlen_param_t;

/* Прототипы функций */
void *spe_test_function(void *data);
int my_strlen(void *ls_base, spe_offset_t data);

/* Ссылка на код SPE */
extern spe_program_handle_t test_handle;

/*  PPE функция обратного вызова */
int my_strlen(void *ls_base_tmp, unsigned int data) {
	char *ls_base = (char *)ls_base_tmp; 
	spe_offset_t params_offset = *((spe_offset_t *)(ls_base + data));
	my_strlen_param_t *params = (my_strlen_param_t *)(ls_base + params_offset);
	char *the_string = ls_base + params->str;
	params->length = strlen(the_string);
	return 0;
}

/* Код для тестирования нашей функции */
int main() {
	pthread_t my_thread;
	int retval;

	/* Регистрация нашего обратного вызова */
	spe_callback_handler_register(my_strlen, 0x10, SPE_CALLBACK_NEW);
	
	retval = pthread_create(&my_thread, NULL, spe_test_function, NULL);
	if(retval) {
		fprintf(stderr, "Error creating thread! Exit code is: %d\n", retval);
		exit(1);
	}

	retval = pthread_join(my_thread, NULL);
	if(retval) {
		fprintf(stderr, "Error joining thread! Exit code is: %d\n", retval);
		exit(1);
	}

	return 0;
}

void *spe_test_function(void *data) {
	int retval;
	unsigned int entry_point = SPE_DEFAULT_ENTRY; 
	spe_context_ptr_t my_context;

	my_context = spe_context_create(SPE_EVENTS_ENABLE|SPE_MAP_PS, NULL);
	spe_program_load(my_context, &test_handle);
	retval = spe_context_run(my_context, &entry_point, 0, NULL, NULL, NULL);
	if(retval) {
		perror("An error occurred running the SPE program");
	}

	pthread_exit(NULL);
}

Далее приведен код SPE, который демонстрирует как заглушку, так и некоторый код, который ее использует (введите как callback_spe.cs):


Листинг 6. Программа для создания заглушки обратного вызова PPE и использование ее
                
#include <sys/send_to_ppe.h>

/* Определение типов */
typedef unsigned int spe_offset_t; 
typedef struct {
	spe_offset_t str; /* Входящий параметр */
	int length; /* Результат */
} my_strlen_param_t;

/* Описание функций */
int my_strlen(char *str);

/* Заглушка обратного вызова */
int my_strlen(char *str) {
	my_strlen_param_t params = { (spe_offset_t)str, 0 };
	__send_to_ppe(0x2110, 0, &params);
	return params.length;
}

/* Пример использования */
int main(unsigned long long spe_id, unsigned long long argp, unsigned long long envp) {
	char *my_str = "Hello there!";
	printf("The length of '%s' is %d\n", my_str, my_strlen(my_str));
	return 0;
}

Для сборки просто сделайте:

spu-gcc callback_spe.c -o spe_callback 
ppu-embedspu test_handle spe_callback spe_callback_csf.o
ppu-gcc -lspe2 -lpthread callback_ppe.c spe_callback_csf.o -o ppe_callback_example 

Функции оценки исключительных состояний в libspe2

Функции оценки исключительных состояний в libspe2 очень похожи на функции в libspe1. Одно различие состоит в том, что все функции в libspe2 используют возвращаемую величину только для статуса, а не для возвращения результатов. Функции libspe2 возвращают ноль при удачном завершении. При ошибке код ошибки будет сохранен в errno. Другое отличие состоит в том, что функции в libspe1 часто используют ID потока SPE (имеющего тип speid_t) в качестве первого параметра, в то время как в libspe2 это обычно указатель контекста SPE (имеющий тип spe_context_ptr_t).

Ниже приведены некоторые различия функций в libspe1 и libspe2:


Таблица 1. Различия функций в libspe1 и libspe2
функции libspe1функции libspe2Комментарии
spe_mfc_* (get, put, getb, etc.)spe_mfcio_*Эти функции работают одинаково в обеих системах.
spe_mfc_read_tag_status_* (all, any или immediate) spe_mfcio_tag_status_read Функция в libspe2 содержит в себе набор возможностей трех функций из libspe1, из-за того что она имеет четвертый параметр, являющийся постоянной, которая сообщает, какую функциональность следует использовать. Пятый параметр в libspe2 — это указатель на возвращаемую величину.
spe_stat_*_mbox spe_*_mbox_status Эти функции эквивалентны.
spe_read_out_mbox spe_out_mbox_read Функция в libspe2 имеет два дополнительных параметра. Второй параметр — указатель на результат. Также в libspe2 один вызов этой функции может возвратить несколько значений. Максимальное число значений, которые следует прочитать, содержит третий параметр. Эта функция также возвращает число прочитанных результатов. Отрицательный результат означает ошибку.
spe_write_in_mbox spe_in_mobx_write Функция в libspe2 гораздо более гибкая. Второй параметр — это указатель на массив величин, которые надо записать, причем число записей сохранено в третьем параметре. Четвертый параметр — это поведение, которое может быть одним из SPE_MBOX_ALL_BLOCKING, которое блокирует, пока все сообщения этой функции не будут записаны, SPE_MBOX_ANY_BLOCKING, которое блокирует, пока хотя бы одно сообщение не будет записано, и SPE_MBOX_ANY_NONBLOCKING, которое записывает то, что может, без блокировки. Функция возвращает число сообщений, которое она может записать в данном состоянии, или -1, если была ошибка.
spe_get_ls spe_ls_area_get Возвращаемая величина для этой функции — указатель в локальном хранилище SPE. При ошибке возвращается NULL и устанавливается errno.

В заключение

Переход на libspe2 предоставляет более гибкую среду для управления SPE-процессами. 2.1 SDK официально возражает против libspe1, так что вскоре этот переход станет важным. libspe2 также содержит дополнительные возможности, такие как регистрация обратных вызовов, что делает программирование SPE более простым.


Ресурсы

Научиться

Получить продукты и технологии

Обсудить

Об авторе

Джонатан Бартлет (Jonathan Bartlett) является автором книги "Программирование с нуля" - введения в программирование на языке ассемблера для Linux. Он является ведущим разработчиком в New Media Worx и занимается Web-приложениями (видео, киосками), а также настольными приложениями для клиентов. Вы можете связаться с ним по адресу johnnyb@eskimo.com.

Помощь по сообщениям о нарушениях

Сообщение о нарушениях

Спасибо. Эта запись была помечена для модератора.


Помощь по сообщениям о нарушениях

Сообщение о нарушениях

Сообщение о нарушении не было отправлено. Попробуйте, пожалуйста, позже.


developerWorks: вход


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


При первом входе в developerWorks для Вас будет создан профиль. Выберите информацию отображаемую в Вашем профиле — скрыть или отобразить поля можно в любой момент.

Выберите ваше отображаемое имя

При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

(Должно содержать от 3 до 31 символа.)


Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Оценить эту статью

Комментарии

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Linux
ArticleID=270612
ArticleTitle=Изменения в libspe: как использование libspe2 изменяет программирование для Cell Broadband Engine
publish-date=11222007
author1-email=johnnyb@eskimo.com
author1-email-cc=

Теги

Help
Используйте форму поиска, чтобы найти любой контент с данным тегом в My developerWorks. Используйте ползунок, чтобы отразить больше или меньше тегов.

КнопкаПопулярные теги отображает самые распространенные теги для данной области контента (например: Java, Linux, WebSphere).

Кнопка Мои теги отображает Ваши теги для данной области контента (например: Java, Linux, WebSphere).

Используйте форму поиска, чтобы найти любой контент с данным тегом в My developerWorks. Кнопка Популярные теги отображает самые распространенные теги для данной области контента (например: Java, Linux, WebSphere). Кнопка Мои теги отображает Ваши теги для данной области контента (например: Java, Linux, WebSphere).