Lapack: هل تسمح بتثبيت محتمل لمكتبة index-64 جنبًا إلى جنب مع مكتبة index-32 القياسية؟

تم إنشاؤها على ١ نوفمبر ٢٠٢٠  ·  41تعليقات  ·  مصدر: Reference-LAPACK/lapack

يحتوي Debian حاليًا (بعض) الرؤوس المنفصلة عن blas64 و cblas64 (وإن لم يكن من التنفيذ المرجعي).

لست متأكدًا مما إذا كانت صحيحة أم لا ، فيما يتعلق بمرجع index64 API (هم من مكتبة blis).

هل سيكون من الممكن إضافة خيار لـ cmake ، شيء مثل BUILD_INDEX64 ، والذي يكون افتراضيًا إلى OFF ، ولكن إذا تم تشغيله ، فسيقوم بإنشاء مكتبات index-64؟
إذا قدمت عرضًا عامًا لمثل هذا الخيار ، فهل سيكون ذلك ممكنًا؟

بعض الأشياء التي كنت أفكر بها للسماح لهذا بالتواجد مع التثبيت القياسي - قم بتسمية المكتبات بـ libblas64.so, libcblas64.so, liblapack64.so, liblapacke64.so ، وبهذه الطريقة لا يوجد تعارض بين أسماء المكتبات (على الرغم من أنه بالطبع ، لا يمكنك الربط مع كل من libblas و libblas64 في نفس الوقت).
ستحتاج أيضًا إلى تجميع المكتبة مرتين ، مرة لـ index32 ومرة ​​لـ index64 (ولكن هذا سيناريو عادي تمامًا وليس عقبة في الصفقات).
الصراع الوحيد الذي لا أستطيع التفكير في حل جيد هو أسماء ملفات الرأس.
إذا كنت تتبع أسلوب دبيان ، فقد يكون من الحكمة استدعاء رؤوس c التي تنتهي بالرقم 64 أيضًا.
(أنا أحافظ على هذا من أجل Gentoo وأود أن أبقي النظام البيئي قريبًا جدًا من دبيان ، بحيث يكون لدينا الحد الأدنى من المشاكل للمطورين الذين يبدلون بين الأنظمة)

أنا منفتح على أي اقتراحات قبل أن أقدم العلاقات العامة: القلب:

شكرا،
عائشة

Build System Enhancement

ال 41 كومينتر

مرحباً عائشة ، هذا منطقي تمامًا بالنسبة لي ، لكن دعنا نرى ما إذا كان لدينا تعليقات من الآخرين. لذلك دعونا ننتظر بضعة أيام. ي

بالتأكيد ، هذا يبدو وكأنه خطة جيدة.

OMGlangou
انت سريع جدا: القلب:

فقط من أجل الاكتمال ، أكتب أشياء لا يزال يتعين علينا القيام بها:

  • اكتشف كيفية تسمية الرؤوس بحيث يمكن لواجهة API 32 بت أن تتعايش مع 64 بت API
  • أصلح عبارات printf / fprintf بحيث تستخدم المؤهل الصحيح للطباعة.

نرحب بأي اقتراحات لحل النقطة الأولى ، للأسف ليس لدي حل "نظيف".

زوجان من الأسئلة ، والتي ستساعدني في التعامل مع تسمية الملفات

  • يبدو أن هناك عددًا كبيرًا من التعريفات المكررة بين cblas_f77.h و cblas_test.h . هل نحن حقا بحاجة إلى ذلك؟
  • هل يلزم تثبيت cblas_test.h ؟ نظرًا لاسمه (والملفات التي يتم استخدامه فيها) أفترض أنه سيتم استخدامه فقط أثناء مرحلة الاختبار. ربما لا ينبغي لنا تثبيت هذا الملف على مستوى النظام بأكمله؟

مرحبًا @ epsilon-0 ،

بعض الأشياء التي كنت أفكر فيها للسماح لهذا بالتواجد مع التثبيت القياسي - قم بتسمية المكتبات بـ libblas64.so ، libcblas64.so ، liblapack64.so ، liblapacke64. لذلك ، بهذه الطريقة لا يوجد تعارض بين أسماء المكتبات ( بالرغم من ذلك بالطبع ، لا يمكنك الارتباط بكل من libblas و libblas64 في نفس الوقت).

قد تبحث عن PR # 218. مؤلف هذا PR هو Björn Esser من مشروع Fedora.

مرحبًا @ epsilon-0. هل حل # 462 هذه المشكلة؟

weslleyspereira لا هذا لم يكتمل بعد.
يجب أن يكون هناك المزيد من عمليات إعادة تسمية / معالجة الرأس.
أنا مشغول خلال الأسابيع القليلة المقبلة ، لذا لن أتمكن من القيام بذلك قريبًا.
المخطط الأساسي

  • يجب تسمية ملفات الرأس cblas.h و cblas64.h ، وبالمثل بالنسبة للرؤوس الأخرى

    • هذا يعني أن ملفات *.c ستحتاج إلى تعديل طفيف لتضمين الرأس المناسب ، ولكن هذا فقط أثناء وقت الإنشاء ، لذلك يمكن اختراقها.

  • يجب تثبيت ملفات cmake تحت lapack64 أو cblas64 ، إلخ.

حسنًا ، فهمت. شكرا على المتابعة السريعة!

لدي مشكلة مماثلة في محاولة حزم الأشياء باستخدام pkgsrc. أود الحصول على تثبيت كامل للمرجع ، مع cblas و lapacke. بالنسبة للتطبيقات المختلفة التي يتم تثبيتها في نفس الوقت ، فقد استقرت على اختلاف أسماء المكتبات والأدلة الفرعية للعناوين ، على سبيل المثال

/usr/lib/libopenblas.so
/usr/lib/libopenblas64.so
/usr/lib/libblas.so
/usr/lib/libcblas.so
/usr/lib/libblas64.so
/usr/lib/libcblas64.so
/usr/include/openblas/cblas.h
/usr/include/openblas64/cblas.h
/usr/include/netlib/cblas.h
/usr/include/netlib64/cblas.h
/usr/include/cblas.h -> netlib/cblas.h (for compatibility, having the default)

(وهكذا دواليك)

نحن لا نفكر في تبديل وقت التشغيل مثل التوزيعات الثنائية ، لذلك لا بأس إذا كان كل cblas.h (و lapacke.h) خاصًا بمكتبته المطابقة ، مثل الأسماء الإضافية لـ libopenblas. يحدث اختيار وقت البناء عبر

BLAS_INCLUDES=-I/prefix/include/netlib64
BLAS_LIBS=-lblas64
CBLAS_LIBS=-lcblas64

(وما إلى ذلك) هذا ما يفترض أن تقوله ملفات .pc ، وهو أسهل كثيرًا من توصيل اسم ملف رأس مختلف. لم يتطابقوا في ذلك بعد ، لكنني أقوم بإصلاحه. يبدو حتى الآن أن الأشخاص قد اخترقوا ذلك في توزيعاتهم ، إذا كانوا يهتمون بكل مراجع مرجعية على الإطلاق.

لدي سؤال واحد حول هذه الرؤوس.

أقوم باختراق بنية cmake للحصول على كل مكون على حدة ، وأحاول بعض الإصلاحات الأخرى (انظر https://github.com/Reference-LAPACK/lapack/pull/556). أحصل على libblas.so و libblas64.so تم بناء المكتبات بشكل جيد ، حصلت على تكوين dirs للرأس ... لكن cblas.h و lapacke.h المثبتان متطابقان لإصدارات الفهرسة 32 و 64 بت. هذا يتعارض مع openblas: هناك ، لدي اختلاف جوهري لا أراه في إصدارات netlib:

diff -ruN /data/pkg/include/openblas/openblas_config.h /data/pkg/include/openblas64/openblas_config.h
--- /data/pkg/include/openblas/openblas_config.h    2021-06-03 19:03:53.000000000 +0200
+++ /data/pkg/include/openblas64/openblas_config.h  2021-06-03 19:13:36.000000000 +0200
@@ -44,6 +44,7 @@
 #define OPENBLAS_DLOCAL_BUFFER_SIZE 32768
 #define OPENBLAS_CLOCAL_BUFFER_SIZE 16384
 #define OPENBLAS_ZLOCAL_BUFFER_SIZE 12288
+#define OPENBLAS_USE64BITINT 
 #define OPENBLAS_GEMM_MULTITHREAD_THRESHOLD 4
 #define OPENBLAS_VERSION " OpenBLAS 0.3.15 "
 /*This is only for "make install" target.*/

بالنسبة للمكتبات المرجعية ، فإن جميع الرؤوس من إصدارات الفهرس 32 بت و 64 بت متطابقة ويبدو أنه من المتوقع أن يضعها المستخدمون
-DWeirdNEC في أعلامهم (ربما كان مضحكًا قبل 30 عامًا) لـ cblas.h و -DLAPACK_ILP64 -DHAVE_LAPACK_CONFIG_H . نظرًا لأن الأشخاص يستخدمون مكتبات BLAS المُحسَّنة في الإنتاج ، فإن المعيار الفعلي هو عدم الكشف عن ذلك للمستخدمين. هذه التغذية المرتدة على المرجع ، IMHO ، والرؤوس المثبتة من بناء ILP64 يجب ألا تتطلب علامات غير تقليدية لتجنب تعطل تطبيقك عند الارتباط بـ 64 بت lib.

هل نتفق على أنه الحل الصحيح لتعديل الرؤوس في وقت البناء لتحديد الأعداد الصحيحة؟

راجع للشغل ، فإن ملفات تكوين cblas التي تم تثبيتها تفتقد أيضًا إلى أي مرجع لملفات defs الضرورية ، لذا فهي معطلة لبنيات فهرس 64 بت ، كما يبدو. لكن في الواقع ، أفكر في عدم تثبيت هذه على الإطلاق. إنها زائدة عن الحاجة مع ملفات .pc وتجعل من الصعب إقناع cmake باستخدام الحزم التابعة لقبول اختيار الحزم عبر BLAS_LIBS etal.

ملاحظة: مع Intel MKL ، هناك مفتاح مركزي -DMKL_ILP64 ليتم ضبطه. أتخيل إقامة تافهة
include/intel-mkl64/cblas.h مع

#ifndef MKL_ILP64
#define MKL_ILP64
#endif
#include <mkl_cblas.h>

لتناسب المخطط العام. يمكنني أيضًا وضع التعريف في BLAS_INCLUDES ، نفس الشيء بالنسبة لتعريفات netlib الغريبة. ايهما افضل؟ هل نريد أن نفعل ذلك مثل Intel أو OpenBLAS؟

هل نتفق على أنه الحل الصحيح لتعديل الرؤوس في وقت البناء لتحديد الأعداد الصحيحة؟

نعم فعلا. أوافق على ذلك ، وأفضل الحل الذي لا يكرر الرأس بالكامل. أعتقد أنه أكثر نظافة.

راجع للشغل ، فإن ملفات تكوين cblas التي تم تثبيتها تفتقد أيضًا إلى أي مرجع لملفات defs الضرورية ، لذا فهي معطلة لبنيات فهرس 64 بت ، كما يبدو.

حق. لقد قمت للتو بتثبيت مكتبات 64 بت (BUILD_INDEX64 = ON) ولم أتمكن من رؤية أي شيء يخبرني باستخدام WeirdNEC أو LAPACK_ILP64 أو HAVE_LAPACK_CONFIG_H . شكرا لملاحظة ذلك!

نعم فعلا. أوافق على ذلك ، وأفضل الحل الذي لا يكرر الرأس بالكامل. أعتقد أنه أكثر نظافة.

هذا أمر غامض بالنسبة لي. ما هو الحل الأنظف؟ ما أقوم بتحضيره الآن هو:

#if defined(WeirdNEC) || @HAVE_ILP64@
   #define CBLAS_INDEX long
   #ifndef WeirdNEC
   #define WeirdNEC
   #endif
#else
   #define CBLAS_INDEX int
#endif

يجب أن يحل ملف CMakeFile محل HAVE_ILP بـ 1 أو 0 ، ويتم تثبيت الرأس الناتج للبناء الحالي.

(راجع للشغل: طويل لن يعمل على Windows. إنه طويل هناك ... أو int64_t على جميع الأنظمة الأساسية مع stdint.)

حق. لقد قمت للتو بتثبيت مكتبات 64 بت (BUILD_INDEX64 = ON) ولم أتمكن من رؤية أي شيء يخبرني باستخدام WeirdNEC أو LAPACK_ILP64 أو HAVE_LAPACK_CONFIG_H . شكرا لملاحظة ذلك!

أنا أتخيل المستقبل حيث تفعل ذلك

cc -I/foo/include/netlib64 -o bar bar.c -L/foo/lib -lcblas64

ويتم التعامل مع الأشياء في foo / include / netlib64 / cblas.h ، وإلا عن طريق foo / include / netlib / cblas.h (ربما يكون مرتبطًا بـ foo / include / cblas.h).

لدي شك في أن هذا _ليس _ ما قصدته ، لكني أريد أن أقنع أنه أفضل ؛-)

يمكنك محاولة عدم تكرار الرأس عن طريق وضع "الرأس" في /foo/include/cblas.h وجعل /foo/include/netlib64/cblas.h يتضمن ذلك فقط عن طريق تعريف WeirdNEC ، ولكن هذا يعني أن الـ 64 تشترك حزم بت و 32 بت في ملف الرأس الشائع ، وهو فوضوي للتعبئة. من الأفضل أن يضع كل واحد ملفه في أماكن / أسماء منفصلة. يجب أن يظل الاسم cblas.h لأنك لا تريد التنقل لاستبدال خطوط #include <cblas.h> .

تحرير: أيضًا ، وجود cblas.h include ../cblas.h يعد أمرًا فوضويًا بحد ذاته. نحدد أيضًا _one_ دليل تثبيت الرأس لـ cmake. بشكل افتراضي ، يكون هذا / foo / include وليس / foo / netlib64 / include. لن أغير هذا الافتراضي. سيتعين على شركات التعبئة تحديد دليل فرعي مثل هذا (BSD make in pkgsrc):

.if !empty(LAPACK_COMPONENT:M*64)
.  if empty(MACHINE_ARCH:M*64)
PKG_FAIL_REASON+=       "${LAPACK_COMPONENT} incompatible with non-64-bit platform"
.  endif
HEADERDIR=netlib64
.else
HEADERDIR=netlib
.endif

# Note: We patch the build to install both static and
# shared libraries.
CMAKE_ARGS=     -DBUILD_DEPRECATED=ON \
                -DBUILD_SHARED_LIBS=ON \
                -DBUILD_STATIC_LIBS=ON \
                -DCMAKE_INSTALL_INCLUDEDIR=${PREFIX}/include/${HEADERDIR} \
                ${LAPACK_COMPONENT_CMAKE_ARGS}

أحد الجوانب الجميلة لشحن / تثبيت cblas.h 32 بت مع هذا التعديل على الموقع المعتاد هو أن الميكانيكا الأصلية لا تزال تعمل. فقط 64 بت متغير سيفرض WeirdNEC. يمكنك أن تقرر تثبيت 64 بت واحد فقط في بادئة والحفاظ على الأجزاء الأخرى من النظام البيئي دون تغيير.

أوه ، هيا ... يبدو أن CBLAS / cmake / cblas-config-install.cmake.in ينسى -DCMAKE_INSTALL_INCLUDEDIR ، أليس كذلك؟

# Report lapacke header search locations.
set(CBLAS_INCLUDE_DIRS ${_CBLAS_PREFIX}/include)

(التعليق هو السكر في الأعلى).

لدي شعور بأن بناء CMake أقل نضجًا بكثير في رأي المرء. هل المشروع جاد في أن يكون ذلك بمثابة بناء أساسي أم أن هذه مجرد مساهمة مدفوعة؟ إنني أميل حقًا إلى إصلاح Makefile ذي الطراز القديم ، وأقل ضجة في كل مكان. لكني الآن أغرقت الكثير من الوقت في إصلاح أشياء CMake ، التي أكرهها على أي حال. لذا أود أن أنهي الأمر.

لا بد لي من الاستسلام الآن ... تمكنت من نقل cblas.h إلى cblas.h.in كما هو موضح أعلاه ، وإضافة

configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cblas.h.in cblas.h @ONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cblas_f77.h.in cblas_f77.h @ONLY)

إلى CBLAS / include / CMakeLists.txt ، بعد أن حددت أيضًا @HAVE_ILP64@ إلى 1 أو 0 في المستوى الأعلى CMakeLists.txt. لكن يمكنني على مدار حياتي ألا أكتشف كيفية جعل عناصر التثبيت الموجودة في CMakeLists.txt ذات المستوى الأعلى تقوم بتثبيت الرؤوس التي تم إنشاؤها ، أو النسخة الغريبة من نفس الشيء من ${LAPACK_BINARY_DIR}/include (حقًا؟ A نسخ داخل شجرة المصدر؟)

ما هو الماكرو append_subdir_files الذي يفترض أن يفعله؟ يبدو أنه يضيف نسخة من البادئة إلى مسارات الرأس. ليس لدي ما يكفي أو الكثير من المسار لملفات رأس المصدر. أريد فقط تثبيت ملفات الرأس من هنا إلى هناك ، اللعنة.

هل يمكن لأي شخص مطلع أن يساعد هنا؟ أعتقد أنه يمكنني معرفة ذلك غدًا ، لكنني لست متأكدًا مما إذا كان ذلك بدون تحطيم شيء ما في العالم الحقيقي من أجل الراحة العاطفية.

نعم فعلا. أوافق على ذلك ، وأفضل الحل الذي لا يكرر الرأس بالكامل. أعتقد أنه أكثر نظافة.

هذا أمر غامض بالنسبة لي. ما هو الحل الأنظف؟ ما أقوم بتحضيره الآن هو:

#if defined(WeirdNEC) || @HAVE_ILP64@
   #define CBLAS_INDEX long
   #ifndef WeirdNEC
   #define WeirdNEC
   #endif
#else
   #define CBLAS_INDEX int
#endif

يجب أن يحل ملف CMakeFile محل HAVE_ILP بـ 1 أو 0 ، ويتم تثبيت الرأس الناتج للبناء الحالي.

(راجع للشغل: طويل لن يعمل على Windows. إنه طويل هناك ... أو int64_t على جميع الأنظمة الأساسية مع stdint.)

حق. لقد قمت للتو بتثبيت مكتبات 64 بت (BUILD_INDEX64 = ON) ولم أتمكن من رؤية أي شيء يخبرني باستخدام WeirdNEC أو LAPACK_ILP64 أو HAVE_LAPACK_CONFIG_H . شكرا لملاحظة ذلك!

أنا أتخيل المستقبل حيث تفعل ذلك

cc -I/foo/include/netlib64 -o bar bar.c -L/foo/lib -lcblas64

ويتم التعامل مع الأشياء في foo / include / netlib64 / cblas.h ، وإلا عن طريق foo / include / netlib / cblas.h (ربما يكون مرتبطًا بـ foo / include / cblas.h).

لدي شك في أن هذا _ليس _ ما قصدته ، لكني أريد أن أقنع أنه أفضل ؛-)

آسف ، اسمحوا لي أن أشرح. في البداية ، أعجبتني فكرة الاحتفاظ بالعنوان الأصلي cblas.h وإنشاء include/netlib64/cblas.h و include/netlib/cblas.h بشيء مثل

#if defined(WeirdNEC)
   #define WeirdNEC
#endif
#include <cblas.h>

يمكنك محاولة عدم تكرار الرأس عن طريق وضع "الرأس" في /foo/include/cblas.h وجعل /foo/include/netlib64/cblas.h يتضمن ذلك فقط عن طريق تعريف WeirdNEC ، ولكن هذا يعني أن الـ 64 تشترك حزم بت و 32 بت في ملف الرأس الشائع ، وهو فوضوي للتعبئة. من الأفضل أن يضع كل واحد ملفه في أماكن / أسماء منفصلة. يجب أن يظل الاسم cblas.h لأنك لا تريد التنقل لاستبدال خطوط #include <cblas.h> .

تحرير: أيضًا ، وجود cblas.h include ../cblas.h يعد أمرًا فوضويًا بحد ذاته. نحدد أيضًا _one_ دليل تثبيت الرأس لـ cmake.

لكن نعم ، سيتعين علينا استخدام include/netlib64 و include كإدراج dirs إذا كان أحد الرؤوس يتضمن الآخر.

بشكل افتراضي ، يكون هذا / foo / include وليس / foo / netlib64 / include. لن أغير هذا الافتراضي. سيتعين على شركات التعبئة تحديد دليل فرعي مثل هذا (BSD make in pkgsrc):

.if !empty(LAPACK_COMPONENT:M*64)
.  if empty(MACHINE_ARCH:M*64)
PKG_FAIL_REASON+=       "${LAPACK_COMPONENT} incompatible with non-64-bit platform"
.  endif
HEADERDIR=netlib64
.else
HEADERDIR=netlib
.endif

# Note: We patch the build to install both static and
# shared libraries.
CMAKE_ARGS=     -DBUILD_DEPRECATED=ON \
                -DBUILD_SHARED_LIBS=ON \
                -DBUILD_STATIC_LIBS=ON \
                -DCMAKE_INSTALL_INCLUDEDIR=${PREFIX}/include/${HEADERDIR} \
                ${LAPACK_COMPONENT_CMAKE_ARGS}

هذا يبدو جيدا بالنسبة لي لذلك ، يمكنك فقط إضافة بديل لبناء LAPACK دون الحاجة إلى _guess_ إشارات المترجم. لكن الطريقة الحالية ستنجح أيضًا.

(راجع للشغل: طويل لن يعمل على Windows. إنه طويل هناك ... أو int64_t على جميع الأنظمة الأساسية مع stdint.)

جيد ان تعلم. يستخدم كل من BLAS ++ و LAPACK ++ int64_t بدلاً من long.

weslleyspereira إذن لقد أحببت هذه الفكرة في البداية:

#if defined(WeirdNEC)
   #define WeirdNEC
#endif
#include "../cblas.h"

مع /prefix/include/cblas.h و /prefix/include/netlib64/cblas.h ، هل يحدد الأخير موقع الأول؟ لكنك توافق الآن على أنه حل أكثر قوة لتثبيت رأس يشبه هذا لبناء 64 بت؟

#if defined(WeirdNEC) || @HAVE_ILP64@
   #define CBLAS_INDEX long
   #ifndef WeirdNEC
   #define WeirdNEC
   #endif
#else
   #define CBLAS_INDEX int
#endif

(لونج مقابل int64 هو أمر مختلف ، لكني أؤيد هذا التغيير ، تمامًا مثل BLAS ++)

هيك ، أنا لست متأكدًا مما إذا كان من الآمن افتراض أن "#include" ... / cblas.h "سيجد فقط العنوان ذي المسافة البادئة الأخرى. يبدو أن معيار C يشير إلى أن أمر البحث معرّف من قبل التنفيذ ، وليس بالضرورة مرتبطًا بالعنوان الحالي. مشكلتي الرئيسية كمحزم هي أنني سأحتاج إلى حزمة منفصلة لذلك الرأس المشترك أو أن حزمة 64 بت تعتمد على 32 بت واحد فقط لذلك. هذا من شأنه أن يمتص.

أود حقًا المضي قدمًا الآن مع مثل هذا التغيير لـ pkgsrc ، لتسوية تغيير في كود المنبع لاحقًا. يمكننا مناقشة رمز جديد لفرض مؤشرات 32 بت أو مؤشرات 64 بت بشكل صريح مع أي من الرؤوس ( -DNETLIB_INDEX_BITS=64 ؟) ، فقط الافتراضي إلى ما تم إنشاء المكتبة به.

هل يمكنني الحصول على اتفاق حول الحل الذي ننوي القيام به على هذا النحو؟

lib/libcblas64.so
include/optional_subdir64/cblas.h

و

lib/libcblas.so
include/optional_subdir/cblas.h

ينتج عن كل بناء من كود LAPACK رؤوس تتطابق افتراضيًا على الأقل مع المكتبات المثبتة دون أن يحدد المستخدم أي شيء. نعم؟

يمكنني بعد ذلك إدخال هذا قبل الإصدار القادم من pkgsrc (اقتراب الموعد النهائي) ويمكننا مناقشة تفاصيل هذا التنفيذ بشكل أكبر حتى أتمكن من إسقاط التصحيحات بعد دمج شيء ما هنا ، مع إصدار LAPACK جديد. مع هذا التغيير ، يحتاج إنشاء Makefile العادي أيضًا إلى الإصلاح ، لكنني لست بحاجة إلى ذلك من أجل تصحيحات _my_ حتى الآن عندما أستخدم بنية CMake.

(تحتاج فقط إلى التحقق بطريقة ما من أعصابي عند محاولة التغلب على بناء CMake الغريب في الإرسال ، حيث يتم خلط نسخ الرؤوس حول أدلة الإنشاء ثم يتعذر العثور عليها للتثبيت. أو تحديد تلك الملفات .cmake المعطلة التي لها أي فائدة لنا ، ربما فقط قم بإسقاطها من التثبيت ... حصلنا على pkg-config!)

اى شى؟ يجب أن أعترف أنني لا أرى فرصة كبيرة لحل مختلف في الممارسة العملية ، لأن هذا هو المثال الذي حددته openblas ، التطبيق الرئيسي الذي نستخدمه. يمكنني أن أتخيل إقناع إنتل بأن يكون لديها دليل فرعي لرؤوس فهرس 64 بت / 32 بت أيضًا ، ملفوفة حول mkl_cblas.h و mkl_lapacke.h. وإلا فإنني أقوم ببناء حزمة بسيطة توفر هذه فقط.

include/mkl-blas/cblas.h
include/mkl-blas64/cblas.h

حاليًا ، أضفت آلات إلى pkgsrc لتقديم تصميمات بخط -DWeirdNEC -DHAVE_LAPACK_CONFIG_H -DLAPACK_ILP64 المضحك ، مع تثبيت كل من cblas و cblas64 رؤوس متطابقة. يمكن أن يظل على هذا النحو ، لكنني ما زلت أعتقد أنه من المنطقي إعداد الرأس لمطابقة البنية ABI.

weslleyspereira إذن لقد أحببت هذه الفكرة في البداية:

#if defined(WeirdNEC)
   #define WeirdNEC
#endif
#include "../cblas.h"

مع /prefix/include/cblas.h و /prefix/include/netlib64/cblas.h ، هل يحدد الأخير موقع الأول؟ لكنك توافق الآن على أنه حل أكثر قوة لتثبيت رأس يشبه هذا لبناء 64 بت؟

#if defined(WeirdNEC) || @HAVE_ILP64@
   #define CBLAS_INDEX long
   #ifndef WeirdNEC
   #define WeirdNEC
   #endif
#else
   #define CBLAS_INDEX int
#endif

نعم هذا كل شيء. أتفق مع الحل الخاص بك لامتلاك مجلدات فرعية لرؤوس 32 بت و 64 بت. لقد ناقشت هذا الأمر مع langou ، وكان مقتنعًا أيضًا أن هذا سيكون حلاً جيدًا.

(لونج مقابل int64 هو أمر مختلف ، لكني أؤيد هذا التغيير ، تمامًا مثل BLAS ++)

حق. يجب معالجة هذا في قضية أخرى.

أود حقًا المضي قدمًا الآن مع مثل هذا التغيير لـ pkgsrc ، لتسوية تغيير في كود المنبع لاحقًا. يمكننا مناقشة رمز جديد لفرض مؤشرات 32 بت أو مؤشرات 64 بت بشكل صريح مع أي من الرؤوس ( -DNETLIB_INDEX_BITS=64 ؟) ، فقط الافتراضي إلى ما تم إنشاء المكتبة به.

هل يمكنني الحصول على اتفاق حول الحل الذي ننوي القيام به على هذا النحو؟

lib/libcblas64.so
include/optional_subdir64/cblas.h

و

lib/libcblas.so
include/optional_subdir/cblas.h

نعم فعلا. أعتقد أنه يمكنك المضي قدمًا واقتراح علاقات عامة في المستقبل ، شكرًا! أنا شخصياً أعتقد أن رمزًا جديدًا مثل NETLIB_INDEX_BITS منطقي تمامًا. أود فقط التأكد من أن القيمة الافتراضية تظل 32 ، وأن -DWeirdNEC يعني -DNETLIB_INDEX_BITS=64 .

ينتج عن كل بناء من كود LAPACK رؤوس تتطابق افتراضيًا على الأقل مع المكتبات المثبتة دون أن يحدد المستخدم أي شيء. نعم؟

يبدو أمرا جيدا لي.

يمكنني بعد ذلك إدخال هذا قبل الإصدار القادم من pkgsrc (اقتراب الموعد النهائي) ويمكننا مناقشة تفاصيل هذا التنفيذ بشكل أكبر حتى أتمكن من إسقاط التصحيحات بعد دمج شيء ما هنا ، مع إصدار LAPACK جديد. مع هذا التغيير ، يحتاج إنشاء Makefile العادي أيضًا إلى الإصلاح ، لكنني لست بحاجة إلى ذلك من أجل تصحيحات _my_ حتى الآن عندما أستخدم بنية CMake.

نعم! من المحتمل أن يكون لدينا إصدار LAPACK في الفصل الدراسي الثاني من عام 2021. ونعم ، يجب تعديل Makefile وفقًا لذلك ، وأنا على استعداد للمساعدة في ذلك.

هذا مرتبط إلى حد ما. يجب ألا ننسى أن رؤوس netlib CBLAS لا يتم توفيرها فقط بواسطة netlib ... تستخدم NumPy دائمًا رأسها الخاص:

https://github.com/numpy/numpy/blob/main/numpy/core/src/common/npy_cblas.h

وفي هذا الرأس ، يتم تعيين CBLAS_INDEX=size_t ، وهو يختلف عن نوع العدد الصحيح المستخدم في تحديد الفهارس. يتم استخدامه فقط لقيم الإرجاع لبعض الوظائف:

$ grep CBLAS_INDEX ./numpy/core/src/common/npy_cblas_base.h                                                                                                                                  
CBLAS_INDEX BLASNAME(cblas_isamax)(const BLASINT N, const float  *X, const BLASINT incX);
CBLAS_INDEX BLASNAME(cblas_idamax)(const BLASINT N, const double *X, const BLASINT incX);
CBLAS_INDEX BLASNAME(cblas_icamax)(const BLASINT N, const void   *X, const BLASINT incX);
CBLAS_INDEX BLASNAME(cblas_izamax)(const BLASINT N, const void   *X, const BLASINT incX);

الاختلاف:

$ grep cblas_isamax ./numpy/core/src/common/npy_cblas_base.h  /data/pkg/include/cblas.h                                                                                                      
./numpy/core/src/common/npy_cblas_base.h:CBLAS_INDEX BLASNAME(cblas_isamax)(const BLASINT N, const float  *X, const BLASINT incX);
/data/pkg/include/cblas.h:CBLAS_INDEX cblas_isamax(const CBLAS_INDEX N, const float  *X, const CBLAS_INDEX incX);

أتساءل عما إذا كان هذا قد يسبب مشكلة. بالنسبة لـ Netlib ، يوجد نوع واحد فقط من الفهرس ، بينما تستخدم التطبيقات الأخرى نوع قيمة إرجاع مختلف لوظائف الفهرس. OpenBLAS يحدد المثال. يقولون أن isamax يُرجع حجمًا بدون إشارة ، لكن غلاف C يستدعي في الواقع دالة فورتران التي تُرجع عددًا صحيحًا مُوقَّعًا (تحرير: روتين فرعي يكتب قيمة عددية 32 بت أو 64 بت إلى مرجع مُسلَّم إلى متغير 64 بت بدون إشارة على 64 أنظمة بت).

هل تطبيق المرجع له رأي في هذا؟ لا توجد مشكلة حقيقية ، لأن قيمة size_t ستكون دائمًا قادرة على الاحتفاظ بأي عائد غير سلبي من isamax (). لكن رائحتها مشكوك فيها. (تحرير: يمكنك إنشاء مؤشرات 64 بت على نظام 32 بت حيث size_t هو 32 بت ، أليس كذلك؟ ثم حصلت على تجاوز. بالإضافة إلى عدم سهولة إرسال size_t * إلى int * .)

نظرًا لأن عمليات التنفيذ المُحسَّنة يبدو أنها قد حددت size_t هناك ، فهل يجب أن يقبل المرجع هذه الحقيقة ويتبعها؟

وما مدى خطورة ربط numpy مع cblas المرجعية؟

OpenBLAS يحدد المثال. (...)
نظرًا لأن عمليات التنفيذ المُحسَّنة يبدو أنها قد حددت size_t هناك ، فهل يجب أن يقبل المرجع هذه الحقيقة ويتبعها؟

بالتأكيد لا يمكنني التحدث عن numpy (أو mkl وما إلى ذلك لهذه المسألة) ، لكنني أتردد في الادعاء بأن OpenBLAS معياري بأي شكل ، على الأقل بالنسبة لما يُنظر إليه (على ما أعتقد) عمومًا على أنه تنفيذ مرجعي .. .

بالتأكيد. كل ما في الأمر أن OpenBLAS أو MKL هما ما يستخدمه الناس في الممارسة ويبدو أنهما قد استقروا عليهما

#define CBLAS_INDEX size_t  /* this may vary between platforms */
#ifdef MKL_ILP64
#define MKL_INT MKL_INT64
#else
#define MKL_INT int
#endif
CBLAS_INDEX cblas_isamax(const MKL_INT N, const float  *X, const MKL_INT incX);

أو بالمثل

#ifdef OPENBLAS_USE64BITINT
typedef BLASLONG blasint;
#else
typedef int blasint;
#endif
#define CBLAS_INDEX size_t
CBLAS_INDEX cblas_isamax(OPENBLAS_CONST blasint n, OPENBLAS_CONST float  *x, OPENBLAS_CONST blasint incx);

مقابل المرجع

#ifdef WeirdNEC
   #define CBLAS_INDEX long
#else
   #define CBLAS_INDEX int
#endif
CBLAS_INDEX cblas_isamax(const CBLAS_INDEX N, const float  *X, const CBLAS_INDEX incX);

فكيف يبتعدون عن المرجع هنا؟ هل كان هناك تواصل حول ذلك؟ أيضًا ... أرى أن MKL و OpenBLAS يحددان مجموعة من الوظائف التي ليست حتى جزءًا من المرجع CBLAS:

CBLAS_INDEX cblas_isamin(const MKL_INT N, const float  *X, const MKL_INT incX);
CBLAS_INDEX cblas_idamin(const MKL_INT N, const double *X, const MKL_INT incX);
CBLAS_INDEX cblas_icamin(const MKL_INT N, const void   *X, const MKL_INT incX);
CBLAS_INDEX cblas_izamin(const MKL_INT N, const void   *X, const MKL_INT incX);

CBLAS_INDEX cblas_isamin(OPENBLAS_CONST blasint n, OPENBLAS_CONST float  *x, OPENBLAS_CONST blasint incx);
CBLAS_INDEX cblas_idamin(OPENBLAS_CONST blasint n, OPENBLAS_CONST double *x, OPENBLAS_CONST blasint incx);
CBLAS_INDEX cblas_icamin(OPENBLAS_CONST blasint n, OPENBLAS_CONST void  *x, OPENBLAS_CONST blasint incx);
CBLAS_INDEX cblas_izamin(OPENBLAS_CONST blasint n, OPENBLAS_CONST void *x, OPENBLAS_CONST blasint incx);

CBLAS_INDEX cblas_ismax(OPENBLAS_CONST blasint n, OPENBLAS_CONST float  *x, OPENBLAS_CONST blasint incx);
CBLAS_INDEX cblas_idmax(OPENBLAS_CONST blasint n, OPENBLAS_CONST double *x, OPENBLAS_CONST blasint incx);
CBLAS_INDEX cblas_icmax(OPENBLAS_CONST blasint n, OPENBLAS_CONST void  *x, OPENBLAS_CONST blasint incx);
CBLAS_INDEX cblas_izmax(OPENBLAS_CONST blasint n, OPENBLAS_CONST void *x, OPENBLAS_CONST blasint incx);

CBLAS_INDEX cblas_ismin(OPENBLAS_CONST blasint n, OPENBLAS_CONST float  *x, OPENBLAS_CONST blasint incx);
CBLAS_INDEX cblas_idmin(OPENBLAS_CONST blasint n, OPENBLAS_CONST double *x, OPENBLAS_CONST blasint incx);
CBLAS_INDEX cblas_icmin(OPENBLAS_CONST blasint n, OPENBLAS_CONST void  *x, OPENBLAS_CONST blasint incx);
CBLAS_INDEX cblas_izmin(OPENBLAS_CONST blasint n, OPENBLAS_CONST void *x, OPENBLAS_CONST blasint incx);

لذا ، فإن تمديد المعيار هو شيء واحد ، ولكن يبدو أن size_t مقابل int يمثل مشكلة خطيرة على أنظمة 64 بت. يجب تسوية هذا بطريقة ما. يبدو لي أن طريقة Netlib معقولة: نفس النوع المستخدم في المؤشرات. كما تستدعي جميع إجراءات فورتران مثل هذا في النهاية

c     isamaxsub.f
c
c     The program is a fortran wrapper for isamax.
c     Witten by Keita Teranishi.  2/11/1998
c
      subroutine isamaxsub(n,x,incx,iamax)
c
      external isamax
      integer  isamax,iamax
      integer n,incx
      real x(*)
c
      iamax=isamax(n,x,incx)
      return
      end

... تسليم عنوان size_t لـ iamax ، يبدو أن هذا خطأ. لم أجد تطبيقًا آخر غير هذا المرجع في مصادر OpenBLAS. هل هم مجرد أغبياء يغيرون النوع الخارجي بهذا الشكل أم أنني أغفل شيئًا أساسيًا جدًا؟ هل يستخدم أي شخص هذه الوظائف بالفعل؟

مرحبًا بالجميع ، المرجع BLAS ، المرجع CBLAS ، المرجع LAPACK ، اثنان من التوجهات الرئيسية لهذه المشاريع هما (1) الخوارزميات العددية و (2) تحديد واجهات مشتركة ، وتنفيذ مرجعي ومجموعة اختبار تذهب إلى هذا. أعتقد أن كل من يشارك في هذه المشاريع يسعده أن ينظر ويتعلم من مشاريع أخرى (OpenBLAS ، MKL ، إلخ) حول هندسة البرمجيات ، وأفضل الممارسات لنشر البرنامج ، وما إلى ذلك. لدينا الكثير لنتعلمه من هذه المشاريع. (كما تعلمنا الكثير من مشاريع الجبر الخطي العددي الأخرى!) على أي حال: المرجع BLAS و CBLAS و LAPACK يمكن أن يستخدم بعض التحسينات في عبوات CMake والواجهات ، وإذا كان OpenBLAS (على سبيل المثال) لديه عملية أفضل ، فهذا مناسب تمامًا لـ نحن ، حسنًا ، أنا جميعًا أؤيد التحرك نحو هذا النموذج.

لإضافة بعض السياق ، وُلد CBLAS من لجنة (المنتدى الفني للبرامج الفرعية للجبر الخطي الأساسي) التي عملت من عام 1996 إلى عام 2000 على إعادة النظر في BLAS ، كجزء من هذا قاموا بتعريف واجهة C لـ BLAS. ارى:
http://www.netlib.org/blas/blast-forum/
انظر على وجه الخصوص:
http://www.netlib.org/blas/blast-forum/cinterface.pdf
أعتقد أن CBLAS الذي يقدمه LAPACK هو تنفيذ للواجهة على النحو المحدد في المنتدى الفني لبرامج الجبر الخطي الأساسية قبل 25 عامًا.

إذا كانت هناك اقتراحات لتحسين CBLAS ، فأرسلها معك. يمكنني محاولة تمرير هذا إلى مختلف أصحاب المصلحة.

شكرا للمؤشر. لذا يبدو أن الجزء ذي الصلة هو B.2.2 في تلك المواصفات ، والتي تنص على أن BLAS_INDEX عادةً ما يكون size_t ، ولكن يمكن أيضًا اختياره ليكون مطابقًا لنوع فورتران الصحيح (الموقّع) المستخدم لـ الفهرسة. الأمر متروك للتنفيذ.

لذلك يبدو أن التطبيقات المحسّنة الشائعة اختارت size_t واختار مرجع Netlib نفس العدد الصحيح الذي يستخدمه لـ Fortran. أرى نسخًا من cblas.h في كل مكان في العديد من المشاريع التي تستخدم lib (مثل numpy ، شحن رأس لـ lib خارجي) ، بهذا السطر

#define CBLAS_INDEX size_t  /* this may vary between platforms */

في https://github.com/LuaDist/gsl/blob/master/cblas/gsl_cblas.h ، يكون هذا مصحوبًا

/* This is a copy of the CBLAS standard header.
 * We carry this around so we do not have to
 * break our model for flexible BLAS functionality.
 */

يبدو أن هذا نشأ في تطبيق المرجع ، ولكن تغير منذ ذلك الحين؟ بالنظر إلى 41779680d1f233928b67f5f66c0b239aecb42774… أرى أن المفتاح CBLAS_INDEX مع WeirdNEC كان موجودًا قبل بناء 64 بت. واو ، هل هذا الالتزام حديثًا. الآن أرى أن size_t كان في المرجع cblas.h حتى عام 2015 ، 83fc0b48afd1f9a6d6f8dddb16e69ed7ed0e7242 بعد تغييره وتقديم تعريف WeirdNEC. لم أتخيل أن هذا حديث جدًا! مربكة للغاية.

أرى أيضًا أن الإصدار السابق من cblas.h سلم int إلى مكالمة fortran ، والآن CBLAS_INDEX . يبدو أن هذا صحيح الآن ، مع الاستخدام المتسق لـ CBLAS_INDEX كنوع عدد صحيح والتبديل لـ 32 أو 64 بت في جزء Fortran.

ولكن هل يمكن أن تكون المكتبات المحسّنة التي ورثت إصدارًا قديمًا من cblas.h مع size_t لكن مصادر المزامنة مع كود CBLAS الحالي من المرجع لديها خطأ لطيف؟ ألا يفعلون شيئًا كهذا لحالة 32 بت على نظام 64 بت؟

#include <stdio.h>
#include <stdlib.h>


void ia_max(int a, void *b)
{
    int *ib = (int*)b;
    *ib = a*2;
}


int main(int argc, char **argv)
{
    int i = atoi(argv[1]);
    size_t maxi;
    ia_max(i, &maxi);
    printf("in %d out %ld\n", i, (long)maxi);
    return 0;
}

وينتج عنه

$ gcc -O -o t t.c
$ ./t 42
in 42 out 140724603453524

إن تنشيط قيمة size_t إلى الصفر يساعد ، ولكن ربما في الحالة الصغيرة فقط. ألا يقع أحد في مشكلة من أجل هذا؟ يجب أن أفتقد شيء ما.

ليستنتج:

  1. يحتوي المرجع CBLAS على size_t كقيمة مرتجعة أولاً.
  2. استخدمت int في المكالمة الفعلية لـ Fortran ، على الرغم من ذلك.
  3. يتم تشغيل المصب (مستخدمو BLAS و CBLAS المحسّنون) بالإصدار القديم من الرأس.
  4. يقدم المرجع CBLAS اختراق WeirdNEC لنظام معين ، مع استبدال size_t بـ int أو long (مطابقة جانب Fortran؟!)
  5. يتم إنشاء واجهة مرجعية 64 بت CBLAS علاوة على ذلك ، باستخدام CBLAS_INDEX كل مكان للعدد الصحيح الافتراضي لـ Fortran.
  6. قام المصب بعمله الخاص مع دعم 64 بت ، ولكن فصله عن CBLAS_INDEX ، وهو دائمًا size_t.
  7. يرث المصب أغلفة CBLAS التي تستخدم CBLAS_INDEX لاستدعاء Fortran الذي يتوقع عددًا صحيحًا افتراضيًا.

هذا يبدو وكأنه كسر رائع نتيجة لذلك. الرؤوس والرمز تباعدت. لماذا لم يلاحظ أحد المشاكل بعد؟ أو هل فاتني الجزء الذي لم يتم فيه استخدام رمز المجمع CBLAS المرجعي لـ isamax والأصدقاء؟

لا يستخدم OpenBLAS على الأقل رمز المجمع CBLAS من Reference-LAPACK (ولم يفعل ذلك مطلقًا ، المصدر موجود ولكن لم يتم بناؤه)

@ martin-frbg جيد أن تعرف. هل يمكنك الإشارة إلى مسار رمز لـ x86-64 ، على سبيل المثال ، يوضح كيفية تمرير size_t إلى الحساب الفعلي لـ cblas_isamax ()؟ لقد وجدت بعض تطبيقات kernel المحددة ولكني لست متأكدًا من الحالة العامة.

سيكون من الجيد معرفة أنه لا أحد يقوم بالفعل بتمرير (size_t*) إلى واجهة Fortran.

من المؤكد أنه ليس من الجيد أن تفترض المشاريع فقط

size_t cblas_isamax(…)

عندما تقدم المكتبة الفعلية عدد صحيح أو طويل (أو int64_t) كقيمة إرجاع. قد تعمل معظم الوقت بقيم في سجلات 64 بت ، لكنها ليست لطيفة. هل يمكننا تصحيح هذا في التطبيقات؟ لم يلتقط الناس مثال Netlib في السنوات الخمس الماضية حول الاستخدام المتزامن لـ CBLAS_INDEX .

الشفرة ذات الصلة موجودة في OpenBLAS / الواجهة ، على سبيل المثال يتم تجميع الواجهة / imax.c إلى cblas_isamax () عندما يتم تعريف CBLAS ، ولا توجد شفرة فورتران متضمنة في مخطط الاستدعاء الخاص بها.

آه جيدة. لذا فإن الحالة الوحيدة التي تمثل مشكلة في الواقع هي الاعتماد على المشاريع باستخدام نسخة من cblas.h لا تناسب المكتبة.

لا أجد الاستخدام الفعلي لـ cblas_isamax() والأصدقاء في NumPy (و SciPy) ، لذلك قد تكون هذه مشكلة نظرية فقط. يجب أن يتم إصلاحه مع ذلك. وبالتالي:

  1. يتبع البعض الآخر مثال Netlib لاستخدام int32_t / int64_t (لنكن صريحين أثناء ذلك ؛-) BLAS_INDEX لكل من إرجاع الحجم ووسيطات الفهرس.
  2. Netlib الكهوف في والعودة إلى size_t لتلك المرتجعات مثل الآخرين.

هل هذه قضية منفصلة للمناقشة؟ ومع ذلك ، فإنه يعيد اختيار مكتبة 32 أو 64 بت.

ملاحظة: ما زلت غير متأكد ما إذا كانت التعدادات في API فكرة جيدة (كنوع بيانات فعلي لوسائط الوظيفة وأعضاء البنية) ، حيث توجد خيارات مترجم لتغيير العدد الصحيح المستخدم تحتها. ليس هذا مناسبًا من الناحية العملية ، لكنه يجعلني غير مرتاح مع ذلك.

كلما فكرت في هذا الأمر ، كلما اتجهت نحو الخيار 2: لقد كان لدينا size_t في واجهة برمجة التطبيقات لفترة طويلة جدًا. ثم قام Netlib بتغيير هذا size_t إلى int أو long. بغض النظر عن أيهما يتطابق بشكل أفضل مع كود Fortran أو قد يكون أكثر اتساقًا ، تم إنشاء size_t لواجهة برمجة التطبيقات (API) وكسر مرجع Netlib ذلك.

هل يجب أن أفتح علاقات عامة حول تغيير الأشياء من أجل

size_t cblas_isamax(const CBLAS_INDEX N, const float  *X, const CBLAS_INDEX incX);
size_t cblas_idamax(const CBLAS_INDEX N, const double *X, const CBLAS_INDEX incX);
size_t cblas_icamax(const CBLAS_INDEX N, const void   *X, const CBLAS_INDEX incX);
size_t cblas_izamax(const CBLAS_INDEX N, const void   *X, const CBLAS_INDEX incX);

تكرارا؟ يجب ألا يكون هناك ماكرو في هذا الموضع بعد الآن للتأكيد على أنه size_t دائمًا ، في كل مكان ، في الماضي والمستقبل.

في https://github.com/numpy/numpy/issues/19243 وصلنا الآن بشكل أساسي إلى: "برغي Netlib ، size_t يعمل للجميع".

هناك ثلاثة أسباب لاستخدام size_t :

  1. تقبل جميع وظائف مكتبة C و C ++ القياسية هذه القيمة وتعيدها ، على سبيل المثال ، void* malloc(size_t) أو size_t strlen() أو std::size_t std::vector<T>::size() (C ++). يؤدي استخدام size_t تجنب اقتطاع القيم والتحويلات الموقعة / غير الموقعة.
  2. غالبًا ما يستخدم size_t للتعبير عن الكميات التي لا يمكن أن تكون سالبة ، مثل أبعاد المصفوفة.
  3. تضمن معايير C و C ++ أنه يمكنك تخزين حجم أي مصفوفة في size_t وأنه يمكنك فهرسة جميع العناصر باستخدام size_t ، cf. cppference.com: size_t .

تحرير: يمكنك البناء باستخدام مؤشرات 64 بت على نظام 32 بت حيث يكون size_t 32 بت ، أليس كذلك؟ ثم حصلت على الفائض.

لا لأن نظام 32 بت قد يحتوي على أكثر من 4 غيغابايت من الذاكرة الظاهرية (يدعم Linux ذلك) ولكن لا يمكن لعملية 32 بت واحدة الوصول إلى أكثر من 4 غيغابايت. أي ، لا يتم استخدام الإصدار 32 بت العلوي من مؤشرات 64 بت مطلقًا.

_ حد الذاكرة لعملية 32 بت تعمل على نظام تشغيل Linux 64 بت_

أعتقد أيضًا أن الحفاظ على size_t هو الشيء الصحيح الذي يجب فعله ، لأن التغيير منه كان انقطاع ABI وجعل Netlib غير متزامن مع بقية العالم.

لكني أشعر بأنني مجبر على التلاعب في حججك ؛-)

1. All of the C and C++ standard library functions accept and return this value

عندما بحثت في هذا الأمر ، عثرت على اعتراف بأنه كان خطأ تاريخيًا في استخدام نوع غير موقع لمؤشرات حاوية C ++ ، وربما حتى نوع الإرجاع لطريقة الحجم () ، حيث ينتهي بك الأمر بسرعة إلى خلط الأرقام الموقعة وغير الموقعة في بطريقة ما. ستكون الحالة الحالية لـ Netlib متسقة مع نفسها ، حيث تستخدم دائمًا الأنواع الموقعة للحجم والمؤشرات ، ولكنها بالطبع غير متوافقة مع malloc() ، والتي تتطلب حجمًا غير موقع حتى تتمكن فعليًا من معالجة كل الذاكرة التي تناسبها 32 بت (أو 64 بت نظريًا).

إنني أتساءل عن حق في ذلك في الكود الذي كتبته حيث قمت في النهاية بتسليم فهرس كإزاحة لاستدعاء وظيفة. الفهرس غير موقعة ، الإزاحة موقعة. بصرف النظر عن المترجمات (MSVC) التي يتم الخلط بينها وبين -unsigned_value ، فإن هذا يعني أنه يجب علي دائمًا القلق بشأن الفائض المحتمل في التحويل.

ولكن على أي حال ، إذا كان الأمر يتعلق فقط بأحجام ذاكرة الحوسبة لتسليمها إلى malloc () والأصدقاء ، فإن size_t هو الشيء الطبيعي ، وقد كان موجودًا من قبل في CBLAS.

في ما يتعلق بالمشكلات المحتملة مع الحالة الحالية للرمز ، عدم التطابق مع إصدارات البائع cblas.h في الإصدارات:

لا لأن نظام 32 بت قد يحتوي على أكثر من 4 غيغابايت من الذاكرة الظاهرية (يدعم Linux ذلك) ولكن لا يمكن لعملية 32 بت واحدة الوصول إلى أكثر من 4 غيغابايت. أي ، لا يتم استخدام الإصدار 32 بت العلوي من مؤشرات 64 بت مطلقًا.

صحيح ، يبقى size_t 32 بت. عندما تقوم (كما قد يكون سخيفًا) ببناء cblas_isamax() لإرجاع عدد صحيح 64 بت ، بعد اختراق البنية لعدم استخدام long ، ولكن int64_t ، بالطبع ، ماذا سوف يحدث حقا في مثل هذا الاستخدام؟

size_t cblas_isamax(); // really int64_t cblas_isamax()!
size_t value = cblas_isamax(…);

قد يضع اصطلاح الاتصال x86 قيمة 64 بت في EAX و EDX. أو قد يعمل مع مؤشر إرجاع وبعض المخزن المؤقت. لكن ماذا ستفعل البنى الأخرى؟ لذلك قد لا تحصل على الفساد ، ولكن بالتأكيد قيمة خاطئة. أفضل حالة هي تجاهل 32 بت الأعلى.

تخيل الآن نظامًا ضخمًا 32 بت (شكل ما من أشكال ARM) ... هل أنت متأكد من أنك ستحصل على النصف المطلوب من القيمة المرتجعة؟

لا يمكنك حقًا العمل مع البيانات غير المتفرقة التي تحتاج إلى مؤشرات 64 بت في برنامج 32 بت ، بالتأكيد. ولكن مجرد القدرة على إجراء استدعاء دالة غير مطابق يعطي _at_least_ نتائج خاطئة يبدو غير صحي.

لقد أجريت بعض الاختبارات السريعة ... على نظام Linux x86 ( gcc -m32 على نظام x86-64) ، ما عليك سوى إسقاط 32 بت العلوية.

الحالة الأكثر إثارة للاهتمام ... حجم 64 بت_:

size_t cblas_isamax(); // really int32_t cblas_isamax()!
size_t value = cblas_isamax(…);

مرة أخرى ، في x86-64 ، فإن العلاقة الغريبة بين 64 بت RAX و 32 بت EAX تجعل الأشياء محددة جيدًا إلى حد ما لتتخلص أيضًا من 32 بت العلوي بصمت بمجرد إجراء عملية 32 بت في السجل المشترك. ولكن هناك متعة في الحصول على تعريف وظيفي غريب بعض الشيء:

$ cat ret32.c 
#include <stdint.h>

int32_t ret64(int64_t a)
{
    a += 1LL<<32;
    return a;
}
$ gcc -m64  -g -c -o ret32.o ret32.c 
$ LANG=C objdump -S ret32.o 
[…]
   8:   48 89 7d f8             mov    %rdi,-0x8(%rbp)
    a += 1LL<<32;
   c:   48 b8 00 00 00 00 01    movabs $0x100000000,%rax
  13:   00 00 00 
  16:   48 01 45 f8             add    %rax,-0x8(%rbp)
    return a;
  1a:   48 8b 45 f8             mov    -0x8(%rbp),%rax

يمكنك أن تجادل فيما إذا كان من الذكاء أن يعمل المترجم على سجل 64 بت كامل ويترك 32 بت العلوية غير واضحة لوظيفة من المتوقع أن ترجع قيمة 32 بت ، لكنها قانونية تمامًا إذا كنت تعتمد على المتصل فقط باستخدام أقل 32 بتًا ، على ما أعتقد.

$ cat call.c 
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

INDEX ret64(int64_t);

int main(int argc, char **argv)
{
    if(argc < 2)
        return 1;
    int64_t a = (int64_t)strtoll(argv[1], NULL, 10);
    INDEX  s = ret64(a);
    printf("%lld\n", (long long)s);
    return 0;
}
$ gcc -m64 -g -DINDEX=int32_t -c -o call32_64.o call.c
$ gcc -m64 -g -DINDEX=size_t -c -o call64_64.o call.c
$ ./call32_64 1
1
$ ./call64_64 1
4294967297

مرح. قيمة إرجاع 32 بت تعطي أكثر مما هو ممكن في 32 بت. هذا ما يمكن أن يحدث (من حيث المبدأ) مع ربط الحالة الحالية لـ Netlib CBLAS بالشفرة التي تتوقع size_t. أعتقد على الرغم من أن 32 بت العلوي من RAX ستكون صفرًا في الكود الفعلي في الممارسة العملية. ولكن من يدري ... يتوقع المترجم من المتصل ألا يستخدم أكثر من 32 بتًا أقل على أي منصة ... قد يقوم أيضًا بتخزين القمامة هناك.

إذن ... هل نتفق على إعادة Netlib إلى size_t كقيمة مرتجعة؟

شكرا على كل هذه التعليقات القيمة!

لقد ناقشت هذا الموضوع قليلاً معlangou. بناءً على المناقشة هنا ، اقتراحي هو:

في علاقات عامة منفصلة:

  1. نعود إلى cblas.h الذي يستخدم تعريفين صحيحين ، دعنا نقول CBLAS_INDEX و CBLAS_INT. هذا ما يحدث في MKL (CBLAS_INDEX و MKL_INT) و OpenBLAS (CBLAS_INDEX و blasint). سيتم استخدام CBLAS_INDEX فقط في عائد i*amax . وبذلك ، نقوم باستعادة ABI المتوافق مع أنظمة BLAS الأخرى.
  2. بالإضافة إلى ذلك ، نختار القيمة الافتراضية لـ CBLAS_INDEX لتكون size_t ونجمع الآراء من المجتمع.

أعتقد أن هذه الفكرة متوافقة (أو ربما نفس) وراء المناقشات الأخيرة في هذا الموضوع.
كما أشار drhpc ،
https://github.com/Reference-LAPACK/lapack/commit/83fc0b48afd1f9a6d6f8dddb16e69ed7ed0e7242 غيّر القيمة الافتراضية لـ CBLAS_INDEX ، و
https://github.com/Reference-LAPACK/lapack/commit/41779680d1f233928b67f5f66c0b239aecb42774 قام بتغيير استخدام CBLAS_INDEX.

فقط لتعزيز:

  • تستخدم OpenBLAS و MKL و GNU Scientific Library و Numpy جميعًا size_t افتراضيًا.
  • تشير واجهة C لـ BLAS (https://www.netlib.org/blas/blast-forum/cinterface.pdf) إلى أنه عادةً ما يكون CBLAS_INDEX = size_t .

هل توافق؟ إذا قمت بذلك ، يمكنني فتح العلاقات العامة. أو ربما تود drhpc القيام بذلك.

أنا موافق. ويرجى فقط المضي قدمًا في العلاقات العامة.

ذكر @ mgates3 لي المناقشة على Slate Google Group:
https://groups.google.com/a/icl.utk.edu/g/slate-user/c/f5y6gt0aoLs/m/oQyyhikwCgAJ
لا يدور النقاش حول ما يجب أن تكون عليه "CBLAS_INDEX" ، بل تدور حول ما يجب أن تكون عليه "CBLAS_INT". هل يجب أن يكون CBLAS_INT هو size_t أم عددًا صحيحًا يحمل توقيعًا أم غير ذلك؟ أعتقد أن المشاركين يصنعون نقاطًا جيدة ، لذا فأنا أمضي معهم.

من فضلك انظر # 588.

صحيح ، يبقى size_t 32 بت. عندما (قد تكون سخيفة) تنشئ cblas_isamax() لإرجاع عدد صحيح 64 بت ، بعد اختراق البنية لعدم استخدام long ، ولكن int64_t ، بالطبع ، ماذا سوف يحدث حقا في مثل هذا الاستخدام؟

size_t cblas_isamax(); // really int64_t cblas_isamax()!
size_t value = cblas_isamax(…);

قد يضع اصطلاح الاتصال x86 قيمة 64 بت في EAX و EDX. أو قد يعمل مع مؤشر إرجاع وبعض المخزن المؤقت. لكن ماذا ستفعل البنى الأخرى؟ لذلك قد لا تحصل على الفساد ، ولكن بالتأكيد قيمة خاطئة. أفضل حالة هي تجاهل 32 بت الأعلى.

تخيل الآن نظامًا ضخمًا 32 بت (شكل ما من أشكال ARM) ... هل أنت متأكد من أنك ستحصل على النصف المطلوب من القيمة المرتجعة؟

هذه اللعبة انتهت. في وحدات المعالجة المركزية Arm ذات 32 بت ، يمكن تمرير أربع قيم 32 بت وإعادتها في السجلات ، وتشغل قيم 64 بت سجلين متتاليين ، راجع القسم _معيار استدعاء الإجراء الخاص بهندسة الذراع _ . بدلاً من الكتابة في سجل واحد ، سوف يقوم المستدعي بفوضى سجلين بأعداد صحيحة 64 بت الخاصة به ؛ من الواضح أن هذه مشكلة. بمجرد نفاد المتصل من سجلات المعلمات ، يتم استخدام المكدس. محاذاة المكدس هي 32 بت ولكن بدلاً من قراءة أو كتابة 32 بت ، يكتب المستدعى 64 بت ؛ مرة أخرى ، انتهت هذه اللعبة وهذه المشكلة (عدم تطابق أحجام القراءة / الكتابة للمكدس) يجب أن تسبب مشاكل في جميع بنيات مجموعة التعليمات في مرحلة ما.

إنني أتساءل عن حق في ذلك في الكود الذي كتبته حيث قمت في النهاية بتسليم فهرس كإزاحة لاستدعاء وظيفة. الفهرس غير موقعة ، الإزاحة موقعة. بصرف النظر عن المترجمات (MSVC) التي يتم الخلط بينها وبين -unsigned_value ، فإن هذا يعني أنه يجب علي دائمًا القلق بشأن الفائض المحتمل في التحويل.

لا ، اللجان القياسية وراء C و C ++ تجعل الكود الخاص بك يتصرف بالطريقة الواضحة في هذه الحالة: إذا كانت u غير موقعة و s قيمة موقعة ، حيث u تحتوي على عدد وحدات بت على الأقل مثل s ، ثم u + s ستؤدي إلى النتيجة الصحيحة رياضيًا ما لم يكن u + s زيادة أو تدفقات سفلية. إذا كانت تحت / تجاوزات ، فستلتف النتيجة ، على سبيل المثال ، (u + s) mod 2^b ، حيث b هو عدد البتات في u و s . من ناحية أخرى ، إذا كان النوع المُوقَّع يمكن أن يمثل جميع قيم النوع غير المُوقَّع ، فسيتم تحويل القيمة غير الموقعة إلى النوع غير المُوقَّع.

البنود ذات الصلة في المسودة القياسية C11 هي كما يلي:

  • 6.2.5.9: العمليات الثنائية مع المعاملات غير الموقعة فقط لا يمكن أن تتجاوز ؛ يتم الحصول على النتيجة بطريقة نمطية MAX + 1 ، حيث MAX هي أكبر قيمة يمكن تمثيلها.
  • 6.3.1.3: نظرًا لقيمة موقعة s ، يتم تحويلها إلى القيمة غير الموقعة s إذا كانت s >= 0 ، وإلا يتم تحويلها إلى s + MAX + 1 .
  • 6.3.1.8: المعاملات الموقعة وغير الموقعة [من نفس الحجم] يتم تحويلها إلى غير موقعة ؛ يتم تحويل المعامل غير الموقّع إلى نوع موقّع إذا كان النوع الموقّع يمكن أن يمثل جميع قيم النوع غير الموقّع

ومن ثم ، سيتم تقييم u + s (بناء الجملة C) إلى

  • (u + s) mod (M + 1) إذا s >= 0 ،
  • (u + s + M + 1) mod (M + 1) خلاف ذلك.

في حالة عدم وجود تجاوز أو انخفاض ، سيتم تقييم هذا التعبير إلى u + s وهو النتيجة المرجوة بشكل حدسي.

عندما بحثت في هذا الأمر ، عثرت على اعتراف بأنه كان خطأ تاريخيًا في استخدام نوع غير موقع لمؤشرات حاوية C ++ ، وربما حتى نوع الإرجاع لطريقة الحجم () ، حيث ينتهي بك الأمر بسرعة إلى خلط الأرقام الموقعة وغير الموقعة في بطريقة ما.

هناك بعض مبرمجي C ++ (بما في ذلك مخترع C ++) الذين يقترحون استخدام الأعداد الصحيحة الموقعة في كل مكان ، راجع الإرشادات الأساسية لـ C ++ ولكنني لن أسمي هذا قبولًا. المشكلة مع سياسة "الأعداد الصحيحة الموقعة في كل مكان" هي

  • التحقق من القيم الدنيا: مع وجود عدد صحيح بدون إشارة ، يكون من غير الضروري في كثير من الحالات التحقق من الحد الأدنى للقيمة ، مع وجود عدد صحيح مرتبط ؛ هذا عرضة للخطأ ويمكن أن يسبب مشاكل أمنية ، انظر على سبيل المثال CWE-839 _ مقارنة النطاق الرقمي بدون حد أدنى من التحقق_ .
  • الفائض: الفائض غير الموقعة له نتيجة محددة جيدًا بينما يمثل تجاوز عدد صحيح موقّع سلوكًا غير محدد.

يمكنك محاولة التحقق من وجود تجاوز موقع بالتعبير a + b < a ولكن قد يقوم المترجم بتحسينه دون سابق إنذار ، انظر على سبيل المثال a إشارة ، ومن المحتمل أن يكون b موقعًا و b يحتوي على عدد من البتات كحد أقصى مثل a ). بالاطلاع على مقال

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات