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).
В 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 до разыменования. Чтобы сделать это, необходимо:
- Иметь
ls_baseкакchar *, чтобы арифметические операции на нем трактовали его как байты. - Сложить SPE-указатель с
ls_base. - Привести результат к указателю соответствующего типа.
- Назначить или разыменовать новый указатель.
Для указателей на указатели (подобных 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" */
/* Мы посылаем ¶ms в эту функцию, но data_offset в действительности имеет
значение &(¶ms) */
spe_offset_t params_offset = *((spe_offset_t *)(ls_base + data));
/* Теперь используем это для поиска значения ¶ms */
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, ¶ms);
/* Возвращаем результат */
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, ¶ms);
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 более простым.
Научиться
-
Changes in libspe: How libspe2 affects Cell Broadband Engine programming (EN) — оригинал
этой статьи на developerWorks.
-
Совершите скачок к грядущим изменениям, прочтя статью
"SPE Runtime Management Library для SDK 2.1 (SPE Runtime Management Library for SDK 2.1)" (EN) (IBM Semiconductor solutions library, март 2007), которая описывает SPE Runtime Management Library, библиотеку, содержащую стандартизованный низкоуровневый интерфейс для доступа к SPE-приложениям Cell/B.E. Имеется справочник по миграции с libspe1 на libspe2, который развивается вместе с библиотекой.
-
Старый, но хороший "POSIX threads explained" (EN) (developerWorks, июль 2000) объясняет как использовать в коде pthreads. Это также делает прекрасное руководство "Программирование POSIX Threads (POSIX Threads Programming) (EN).
-
Вместе с экспертами Марком Нуттером (Mark Nutter) и Максом Агуиляром (Max Aguilar) изучите статью Модель памяти Cell/B.E. (EN) (developerWorks, апрель 2006).
- Статья
"Введение в мультипроцессор Cell (Introduction to the Cell Multiprocessor)" (EN) (IBM Journal of Research and Development, 2005) дает вводный обзор истории мультипроцессора Cell/B.E., целей и проблем программы, концепции дизайна, модели архитектуры и программирования и реализации.
-
Справочник по установке SDK 2.1 (Software Development Kit 2.1 Installation Guide Version 2.1) (PDF) проведет вас через установку и конфигурирование и познакомит с основами, которые необходимо знать, чтобы начать разработку. Два близких текста
"Cell/B.E. SDK 2.1: Установка Fedora Core 6 (Cell/B.E. SDK 2.1: Setting up Fedora Core 6)" (EN) и "Cell/B.E. SDK 2.1: Введение в терминологию (Cell/B.E. SDK 2.1: Understanding the terminology)" (EN) (developerWorks, апрель 2007) могут помочь в подготовке и запуске FC6 и обеспечат справочником по терминологии Cell/B.E.
-
Чтобы больше узнать о программировании на Cell/B.E., просмотрите серию статей
"Программирование высокопроизводительных приложений на процессоре Cell/B.E. (Programming high-performance applications on the Cell/B.E. processor)" , а также статьи "PS3 fab to lab" (EN) и "Небольшой широкополосный сервер (The little broadband engine that could)" (EN).
Получить продукты и технологии
-
Последний выпуск Cell/B.E. SDK, версия 2.1 содержит основную часть разработки Cell/B.E.(EN)
-
DeveloperWorks Cell Broadband Engine Resource Center — это информационный центр, содержащий связанные с Cell/B.E. ресурсы, загрузки и новости.(EN)
Обсудить
- Примите участие в обсуждении материала на форуме.
-
Форум Cell Broadband Engine Architecture
— то место, где вы получите ответы на технические вопросы, связанные с процессором. (Различные проблемы и ответы из форума периодически обсуждаются и освещаются в блогах "Forum watch".) (EN)
- Страница
Блоги архитектуры Power предоставляет новости, загрузки, инструкции и извещения о событиях для Cell/B.E. и других относящихся к архитектуре Power технологий и является родиной двух серий блогов — "Forum watch" (Q&A roundup) и обновление технологий "FixIt".(EN)
-
Эта контактная страница даст вам возможность обсудить решения для процессора Cell/B.E. с представителями IBM.(EN)
Джонатан Бартлет (Jonathan Bartlett) является автором книги "Программирование с нуля" - введения в программирование на языке ассемблера для Linux. Он является ведущим разработчиком в New Media Worx и занимается Web-приложениями (видео, киосками), а также настольными приложениями для клиентов. Вы можете связаться с ним по адресу johnnyb@eskimo.com.