Amazon Best VPN GoSearch

Значок OnWorks

PDL::Internalsp - онлайн у хмарі

Запустіть PDL::Internalsp у постачальника безкоштовного хостингу OnWorks через Ubuntu Online, Fedora Online, онлайн-емулятор Windows або онлайн-емулятор MAC OS

Це команда PDL::Internalsp, яку можна запустити в постачальнику безкоштовного хостингу OnWorks за допомогою однієї з наших безкоштовних робочих станцій, таких як Ubuntu Online, Fedora Online, онлайн-емулятор Windows або онлайн-емулятор MAC OS.

ПРОГРАМА:

ІМ'Я


PDL::Internals - опис деяких аспектів поточних внутрішніх компонентів

ОПИС


Введення
Цей документ пояснює різні аспекти поточної реалізації PDL. Якщо ти просто
ви хочете використовувати PDL для чогось, вам точно не потрібно це читати. Навіть якщо ти хочеш
щоб підключити ваші підпрограми C до PDL або створити нові функції PDL::PP, вам не потрібно
прочитайте цю man-сторінку (хоча вона може бути інформативною). Цей документ в першу чергу призначений для
людей, зацікавлених у налагодженні або зміні внутрішніх компонентів PDL. Щоб прочитати це, добре
розуміння мови C і програмування і структур даних в цілому є
необхідно, а також певне розуміння Perl. Якщо ви прочитаєте цей документ і
розуміють все це і можуть вказати, на що посилається будь-яка частина цього документа
Основні джерела PDL і, крім того, намагаються зрозуміти PDL::PP, ви отримаєте
титул «Гуру PDL» (звичайно, поточна версія цього документа настільки неповна, що
це майже неможливо лише з цих нотаток).

Увага! Якщо здається, що цей документ застарів, повідомте про це PDL
список електронної пошти вантажників ([захищено електронною поштою]). Це цілком може статися.

Підлі
Об’єкт даних pdl, як правило, є непрозорим скалярним посиланням на структуру pdl
пам'ять. Крім того, це може бути хеш-посилання з полем «PDL», що містить
скалярне посилання (це полегшує перевантаження piddles, див. PDL::Objects). Ви можете легко
дізнайтеся на рівні Perl, з яким типом piddles ви маєте справу. Приклад коду
нижче показано, як це зробити:

# перевірте, чи це піддл
die "не піддл", якщо UNIVERSAL::isa($pdl, 'PDL');
# це скалярне чи хешове посилання?
if (UNIVERSAL::isa($pdl, "HASH")) {
die "недійсний PDL", якщо не існує $pdl->{PDL} &&
UNIVERSAL::isa($pdl->{PDL},'PDL');
print "Це хеш-посилання,",
" поле PDL містить скалярне посилання\n";
} Ще {
print "Це скалярне посилання, яке вказує на адресу $$pdl в пам'яті\n";
}

Скалярне посилання вказує на числову адресу структури C типу "pdl", яка є
визначено в pdl.h. Відображення між об’єктом на рівні Perl і структурою C
PDL, що містить фактичні дані та структурну, що складає piddle
typemap. Функції, які використовуються в карті типів PDL, визначені майже вгорі
файл pdlcore.h. Отже, як виглядає конструкція:

struct pdl {
unsigned long magicno; /* Завжди зберігає PDL_MAGICNO як перевірку працездатності */
/* Це перше, тому більшість звернень вказівників до неправильного типу ловляться */
int стан; /* Що в цьому файлі Pdl */

pdl_trans *trans; /* Непрозорий покажчик на внутрішні елементи перетворення з
батько */

pdl_vaffine *vafftrans;

порожнеча* св; /* (необов'язковий) покажчик назад до вихідного sv.
ЗАВЖДИ перевіряйте, чи немає значення null перед використанням.
Ми не можемо впливати на це, інакше ми б хотіли
ніколи не бути знищеним */

void *datasv; /* Вказівник на SV, що містить дані. Refcnt inced */
недійсні *дані; /* Null: для цього немає даних */
PDL_Indx nvals; /* Скільки значень виділено */
тип даних int;
PDL_Indx *dims; /* Масив розмірів даних */
PDL_Indx *зменшення; /* Масив приростів даних за замовчуванням */
короткі ndims; /* Кількість параметрів даних */

unsigned char *threadids; /* Початковий індекс набору індексів потоку n */
unsigned char nthreadids;

pdl *попередник; /* Я в мутованій родині. make_physical_now повинен
копіюйте мене в нове покоління. */
pdl *future_me; /* Я «тоді» pdl, а це мій «зараз» (або більш сучасний
версія, у всякому разі */

pdl_children діти;

коротке життя_для; /* Сторона Perl не посилається; видаліть мене, коли */

PDL_Indx def_dims[PDL_NDIMS]; /* Попередньо виділений простір для ефективності */
PDL_Indx def_dimincs[PDL_NDIMS]; /* Попередньо виділений простір для ефективності */
unsigned char def_threadids[PDL_NTHREADIDS];

struct pdl_magic *магія;

void *hdrsv; /* "заголовок", налаштовується ззовні */
};

Це досить структура для простого зберігання деяких даних - що відбувається?

зберігання даних
Ми почнемо з деяких простіших членів: перш за все, це
член

недійсний *datasv;

який насправді є вказівником на структуру Perl SV ("SV *"). Очікується, що SV буде
що представляє собою рядок, в якому дані piddle зберігаються в щільно упакованому
форму. Цей покажчик вважається посиланням на SV, тому кількість посилань була
збільшується, коли тут розміщується "SV *" (це має зробити бізнес підрахунку посилань
з механізмом збирання сміття Perl - не хвилюйтеся, якщо це не має великого значення
ти). Цей покажчик може мати значення "NULL", що означає, що його немає
фактичний Perl SV для цих даних - наприклад, дані можуть бути виділені "mmap"
операція. Зверніть увагу, що використання SV* було суто для зручності, це дозволяє легко
перетворення упакованих даних з файлів у piddles. Інші реалізації ні
виключено.

Фактичний покажчик на дані зберігається в члені

недійсні *дані;

який містить вказівник на область пам’яті з місцем для

PDL_Indx nvals;

елементи даних типу даних цього piddle. PDL_Indx є або «довгим» або «довгим довгим»
залежно від того, чи є ваш perl 64-бітним чи ні.

Тип даних зберігається у змінній

тип даних int;

значення для цього члена вказані в переліку "pdl_datatypes" (див pdl.h).
На даний момент ми маємо типи byte, short, short, long, float і double, див. також
PDL::Типи.

розміри
Кількість розмірів у piddle задається членом

int ndims;

який показує, скільки записів є в масивах

PDL_Indx *тьмяніє;
PDL_Indx *зменшення;

Ці масиви тісно пов'язані: "dims" дає розміри розмірів і
"dimincs" завжди обчислюється кодом

PDL_Indx inc = 1;
for(i=0; i ndims; i++) {
it->dimincs[i] = inc; inc *= it->dims[i];
}

у підпрограмі "pdl_resize_defaultincs" у "pdlapi.c". Це означає, що
dimincs можна використовувати для обчислення зміщення за кодом, як

PDL_Indx offs = 0;
for(i=0; i ndims; i++) {
offs += it->dimincs[i] * index[i];
}

але це не завжди правильно, принаймні без перевірки напевно
речі в першу чергу.

Сховище за замовчуванням
Оскільки переважна більшість piddles не має більше 6 вимірів, це більше
ефективно мати сховище за замовчуванням для розмірів і розмірів всередині PDL
структура.

PDL_Indx def_dims[PDL_NDIMS];
PDL_Indx def_dimincs[PDL_NDIMS];

Параметри "dims" і "dimincs" можуть бути встановлені так, щоб вони вказували на початок цих масивів, якщо
"ndims" менше або дорівнює константі часу компіляції "PDL_NDIMS". Це
важливо звернути увагу під час звільнення структури piddle. Те ж саме стосується ниток:

unsigned char def_threadids[PDL_NTHREADIDS];

магія
До piddles можна приєднати магію, як і власний магічний механізм Perl. Якщо
покажчик члена

struct pdl_magic *магія;

відмінний від нуля, PDL має певну магію. Реалізація магії може бути
взято з файлу pdlmagic.c в розподілі.

стан
Одним із перших членів структури є

int стан;

Можливі прапори та їх значення наведені в "pdl.h". До них в основному звикли
реалізуйте механізм лінивого оцінювання та відстежуйте в них додатки
операції.

Перетворення та віртуальні афінні перетворення
Як ви вже знаєте, підлі часто несуть інформацію про те, звідки вони надходять
від Наприклад, код

$b = $a->slice("2:5");
$b .= 1;

змінить $a. Отже, $b і $a Знати що вони з’єднані через a
«зріз»-перетворення. Ця інформація зберігається в учасниках

pdl_trans *trans;
pdl_vaffine *vafftrans;

Обидва $a (the батько) і $b (дитина) зберігають цю інформацію про
перетворення у відповідні слоти структури «pdl».

"pdl_trans" і "pdl_vaffine" - це структури, які ми розглянемо більш детально
нижче.

Perl SV
Коли до piddles посилаються через Perl SV, ми зберігаємо додаткове посилання на нього
в члені

порожнеча* св;

щоб мати можливість повернути посилання користувачеві, коли він хоче перевірити
структура трансформації на стороні Perl.

Також зберігаємо непрозорий

недійсний *hdrsv;

яка призначена лише для використання користувачем для підключення довільних даних за допомогою цього sv. Ось цей
зазвичай маніпулюють за допомогою викликів sethdr і gethdr.

Smart посилання та трансформації: нарізка та різання кубиками
Реалізовано розумні посилання та більшість інших фундаментальних функцій, що працюють на piddles
через перетворень (Як згадувалося вище), які представлені типом "pdl_trans" в
PDL.

Трансформація пов’язує вхідні та вихідні модулі та містить всю інфраструктуру
визначає як

· вихідні піктограми отримують з вхідних

· зміни в розумно зв'язаних вихідних модулях (наприклад, дитина нарізаного батько паскудка)
повертаються до вхідного piddle у перетвореннях, де це підтримується (
найчастіше вживаний приклад - "сріз").

· отримано тип даних і розмір вихідних piddles, які необхідно створити

Загалом, виконання функції PDL для групи piddles призводить до створення a
перетворення запитуваного типу, яке пов’язує всі вхідні та вихідні аргументи (принаймні
ті, що є піддлами). У PDL функції, які підтримують потік даних між входом і виводом
args (наприклад, "зріз", "індекс") це перетворення посилає батько (вхід) і дитина (вихід)
piddles постійно до тих пір, поки посилання не буде явно зламано за запитом користувача ("sever" at
рівень Perl) або всі батьки та діти були знищені. У тих випадках
перетворення оцінюється з відкладенням, наприклад, виконується лише тоді, коли значення piddle є фактичними
доступ.

In непроточний функції, наприклад додавання ("+") і внутрішні продукти ("внутрішній"),
трансформація встановлюється так само, як і в проточних функціях, але потім перетворення є
негайно виконується та знищується (порушення зв’язку між вхідними та вихідними аргументами)
до повернення функції.

Слід зазначити, що тісний зв'язок між вхідними і вихідними аргументами протікає функції
(наприклад, slice) вимагає, щоб об'єкти piddle, які пов'язані таким чином, залишалися живими
за межі точки, де вони вийшли за рамки з точки зору Perl:

$a = нулі(20);
$b = $a->slice('2:4');
undef $a; # останнє посилання на $a тепер знищено

Хоча $a тепер має бути знищено відповідно до правил Perl, основний «pdl»
Структура має бути звільнена лише тоді, коли $b також виходить за межі області дії (оскільки вона все ще
посилається внутрішньо на деякі дані $a). Цей приклад демонструє, що такий потік даних
Парадигма між об'єктами PDL вимагає спеціального алгоритму знищення, який приймає
враховують зв’язки між піддлами та поєднують тривалість життя цих об’єктів. не-
тривіальний алгоритм реалізований у функції «pdl_destroy» в pdlapi.c. Насправді більшість
коду в pdlapi.c та pdlfamily.c піклується про те, щоб piddles ("pdl
*"s) створюються, оновлюються та звільняються в потрібний час залежно від взаємодії з
інші piddles через PDL-перетворення (запам'ятайте, "pdl_trans").

Доступ до діти та батьки of a калюжка
Коли piddles динамічно пов’язані за допомогою перетворень, як запропоновано вище, введіть і
вихідні пікселі називаються відповідно батьками та дітьми.

Приклад обробки дітей piddle наведено методом «baddata».
PDL::Bad (доступно, лише якщо ви зібрали PDL з параметром "WITH_BADVAL", установленим на 1,
але все одно корисний як приклад!).

Розглянемо таку ситуацію:

pdl> $a = rvals(7,7,Centre=>[3,4]);
pdl> $b = $a->slice('2:4,3:5');
pdl> ? вар
Змінні PDL в пакеті main::

Назва Тип Розмір Потік Стан Мем
-------------------------------------------------- --------------
$a Подвійний D [7,7] P 0.38Kb
$b Double D [3,3] VC 0.00Kb

Тепер, якщо я раптом вирішу, що $a має бути позначено як таке, що, можливо, містить погані значення,
використання

pdl> $a->погані дані(1)

тоді я хочу стан $b - це дитина - також буде змінено (оскільки це також буде
ділитися або успадковувати деякі дані $a і таким чином бути поганий), щоб я отримав 'B' в стан
поле:

pdl> ? вар
Змінні PDL в пакеті main::

Назва Тип Розмір Потік Стан Мем
-------------------------------------------------- --------------
$a Double D [7,7] PB 0.38Kb
$b Double D [3,3] VCB 0.00 Кб

Ця магія виконується функцією propogate_badflag, яка наведена нижче:

/* newval = 1 означає встановити прапор, 0 означає очистити його */
/* дякую Крістіану Соллеру за це */

void propogate_badflag( pdl *it, int newval ) {
PDL_DECL_CHILDLOOP(it)
PDL_START_CHILDLOOP(це)
{
pdl_trans *trans = PDL_CHILDLOOP_THISCHILD(це);
int i;
for( i = trans->vtable->nparents;
i < trans->vtable->npdls;
i++ ) {
pdl *child = trans->pdls[i];

if ( newval ) child->state |= PDL_BADVAL;
else child->state &= ~PDL_BADVAL;

/* переконайтеся, що ми пропагуємо онуків тощо */
propogate_badflag( дитина, newval );

} /* для: i */
}
PDL_END_CHILDLOOP(це)
} /* propogate_badflag */

Враховуючи piddle ("pdl *it"), програма проходить цикл через кожну структуру "pdl_trans", де
доступ до цієї структури надається макросом "PDL_CHILDLOOP_THISCHILD". The діти
piddle зберігаються в масиві "pdls" після батьки, отже, цикл з "i =
...nparents" до "i = ...nparents - 1". Після того, як ми маємо вказівник на дочірній piddle, ми
можемо робити з цим те, що хочемо; тут ми змінюємо значення змінної "state", але
деталі неважливі). Що is Важливо, що ми викликаємо "propogate_badflag" для цього
piddle, щоб переконатися, що ми перебираємо його дітей. Ця рекурсія гарантує, що ми дістанемося до всіх
потомство конкретної підлі.

Доступ до батьки подібний, із заміною циклу "for" на:

for( i = 0;
i < trans->vtable->nparents;
i++ ) {
/* робити щось із батьківським #i: trans->pdls[i] */
}

Що in a перетворення ("pdl_trans")
Усі перетворення реалізуються у вигляді структур

структура XXX_trans {
int magicno; /* для виявлення перезапису пам'яті */
короткі прапорці; /* стан транс*/
pdl_transvtable *vtable; /* всі важливі vtable */
void (*freeproc)(struct pdl_trans *); /* Зателефонуйте, щоб звільнити цей транс
(на випадок, якщо нам довелося щось розкрити для цього trans) */
pdl *pdls[NP]; /* Pdl, залучений до перетворення */
int __тип даних; /* тип перетворення */
/* загалом більше членів
/* залежно від фактичного перетворення (зріз, додавання тощо)
*/
};

Трансформація ідентифікує всі "pdl", які беруть участь у трансляції

pdl *pdls[NP];

з "NP" залежно від кількості аргументів piddle конкретного транс. Він записує а
були

короткі прапорці;

і тип даних

int __тип даних;

транс (до якого всі piddles повинні бути перетворені, якщо вони не введені явно, PDL
функції, створені за допомогою PDL::PP, переконаються, що ці перетворення виконуються за потреби).
Найважливішим є вказівник на vtable (віртуальну таблицю), яка містить фактичний
функціональність

pdl_transvtable *vtable;

Структура vtable, у свою чергу, виглядає приблизно так (трохи спрощено з pdl.h та цінності
ясність)

typedef struct pdl_transvtable {
pdl_transtype транстип;
прапори int;
int nparents; /* кількість батьківських pdl (вхід) */
int npdls; /* кількість дочірніх pdl (вихід) */
char *per_pdl_flags; /* прапорці оптимізації */
void (*redodims)(pdl_trans *tr); /* з'ясувати тьмяність дітей */
void (*readdata)(pdl_trans *tr); /* передати батьків дітям */
void (*writebackdata)(pdl_trans *tr); /* потік назад */
void (*freetrans)(pdl_trans *tr); /* Звільняє як вміст, так і його
транс-член */
pdl_trans *(*copy)(pdl_trans *tr); /* Повна копія */
int structsize;
char *ім'я; /* Здебільшого для відладчиків */
} pdl_transvtable;

Ми зосередимося на функціях зворотного виклику:

void (*redodims)(pdl_trans *tr);

"redodims" опрацює розміри piddles, які потрібно створити, і називається
з функції API, яку слід викликати, щоб переконатися, що розміри a
piddle доступні (pdlapi.c):

void pdl_make_physdims(pdl *it)

«readdata» і «writebackdata» відповідають за фактичні обчислення дитини
дані батьків або батьківські дані від дітей відповідно (
аспект потоку даних). Ядро PDL гарантує, що вони викликаються за потреби під час piddle
доступ до даних (lazy-evaluation). Загальна функція API, щоб переконатися, що piddle є
актуальним є

void pdl_make_physvaffine(pdl *it)

який слід викликати перед доступом до даних piddle з XS/C (див Core.xs для деяких
приклади).

"freetrans" звільняє динамічно виділену пам'ять, пов'язану з trans, за потреби та
"copy" може скопіювати перетворення. Знову ж таки, функції, створені за допомогою PDL::PP, переконаються в цьому
копіювання та звільнення за допомогою цих зворотних викликів відбувається в потрібний час. (Якщо вони не зроблять
що у нас витік пам'яті - це траплялося в минулому ;).

Код трансформації та vtable майже ніколи не пишеться вручну, а генерується за допомогою
PDL::PP із стислих описів.

Певні типи перетворень можна оптимізувати дуже ефективно, уникаючи необхідності
явні методи "readdata" і "writebackdata". Ці перетворення називаються
pdl_vaffine. Більшість функцій маніпулювання розмірами (наприклад, "зріз", "xchg") належать до цього
клас.

Основна хитрість полягає в тому, що батько і дитина такої трансформації працюють над тим самим
(спільний) блок даних, який вони просто вирішують інтерпретувати по-різному (використовуючи різні
"dims", "dimincs" і "off" на тих самих даних, порівняйте структуру "pdl" вище). Кожен
Таким чином, операція з piddle обмінюється даними з іншим таким чином автоматично
перелітають від дитини до батьків і назад – адже вони читають і пишуть одне й те саме
блок пам'яті. На даний момент це не безпечно для потоків Perl – немає великих втрат, оскільки весь PDL
ядро не є реентерабельним (Perl threading "!=" PDL threading!).

Підписи: різьблення над елементарний операції
Більшість цієї функціональності потоків PDL (автоматична ітерація елементарних операцій
над multi-dim piddles) реалізовано у файлі pdlthread.c.

Функції, згенеровані PDL::PP (зокрема, "readdata" і "writebackdata"
зворотні виклики) використовують цю інфраструктуру, щоб переконатися, що фундаментальна операція реалізована
за допомогою trans виконується згідно з семантикою потоків PDL.

Визначення new PDL Функції -- Клей код покоління
Будь ласка, перегляньте PDL::PP та приклади в дистрибутиві PDL. Реалізація та синтаксис є
на даний момент далекий від досконалості, але він робить хорошу роботу!

Команда Core структура
Як обговорювалося в PDL::API, PDL використовує вказівник на структуру, щоб дозволити модулям PDL доступ до
його основні рутини. Визначення цієї структури (структура «Ядро») знаходиться в pdlcore.h
(створений pdlcore.h.PL in Базовий/Ядро) і виглядає приблизно так

/* Структура для утримання покажчиків основних підпрограм PDL для використання
* багато модулів
*/
struct Core {
Версія I32;
pdl* (*SvPDLV) (SV*);
void (*SetSV_PDL) (SV *sv, pdl *it);
#якщо визначено (PDL_clean_namespace) || визначено (PDL_OLD_API)
pdl* (*новий) ( ); /* змусити його працювати з gimp-perl */
#else
pdl* (*pdlnew) ( ); /* перейменовано через зіткнення C++ */
#endif
pdl* (*tmp) ();
pdl* (*створити) (тип int);
void (*знищити) (pdl *it);
...
}
typedef struct Core Core;

Перше поле структури («Версія») використовується для забезпечення узгодженості між модулями
під час виконання; наступний код розміщується в розділі BOOT згенерованого коду xs:

якщо (PDL->Версія != PDL_CORE_VERSION)
Perl_croak(aTHX_ "Foo потрібно перекомпілювати для щойно встановленого PDL");

Якщо ви додаєте нове поле до Core структуру ви повинні:

· обговоріть це в списку електронних листів Pdl Porters ([захищено електронною поштою]) [з
можливість внесення змін до окремої гілки дерева CVS, якщо це a
зміна, для завершення якої знадобиться час]

· збільшити на 1 значення змінної $pdl_core_version в pdlcore.h.PL. Це набори
значення макросу "PDL_CORE_VERSION" C, що використовується для заповнення поля Версія

· додати документацію (наприклад, до PDL::API), якщо це «корисна» функція для зовнішнього модуля
автори (а також переконання, що код так само добре задокументований, як і решта PDL;)

Використовуйте PDL::Internalsp онлайн за допомогою служб onworks.net


Безкоштовні сервери та робочі станції

Завантажте програми для Windows і Linux

Команди Linux

Ad




×
реклама
❤️Робіть покупки, бронюйте або купуйте тут — безкоштовно, це допомагає зберегти послуги безкоштовними.