Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Proposal] Improve public API #217

Open
toor1245 opened this issue Jan 18, 2022 · 1 comment
Open

[Proposal] Improve public API #217

toor1245 opened this issue Jan 18, 2022 · 1 comment
Labels
enhancement New feature or request

Comments

@toor1245
Copy link
Contributor

toor1245 commented Jan 18, 2022

It would be great to improve the public API for porting the library.

My proposal is to add macro CPU_FEATURES_EXPORT to include/cpu_features_macros.h and add to public functions this export macro.

// include/cpu_features_macros.h
#if defined(CPU_FEATURES_COMPILER_MSC)
#if !defined(CPU_FEATURES_SHARED_LIB)
#define CPU_FEATURES_EXPORT
#elif defined(CPU_FEATURES_SHARED_LIB_EXPORT)
#define CPU_FEATURES_EXPORT __declspec(dllexport)
#else
#define CPU_FEATURES_EXPORT __declspec(dllimport)
#endif
#elif defined(CPU_FEATURES_COMPILER_GCC)
#if defined(CPU_FEATURES_SHARED_LIB) && defined(CPU_FEATURES_SHARED_LIB_EXPORT)
#define CPU_FEATURES_EXPORT __attribute__((visibility("default")))
#else
#define CPU_FEATURES_EXPORT
#endif
#else
#define CPU_FEATURES_EXPORT
#endif

// cpuinfo_x86.h
CPU_FEATURES_EXPORT X86Info GetX86Info(void);

however we have one point with shared library

# BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to make
# it prominent in the GUI.
# cpu_features uses bit-fields which are - to some extends - implementation-defined (see https://en.cppreference.com/w/c/language/bit_field).
# As a consequence it is discouraged to use cpu_features as a shared library because different compilers may interpret the code in different ways.
# Prefer static linking from source whenever possible.
option(BUILD_SHARED_LIBS "Build library as shared." OFF)
# Force PIC on unix when building shared libs
# see: https://en.wikipedia.org/wiki/Position-independent_code
if(BUILD_SHARED_LIBS AND UNIX)
option(CMAKE_POSITION_INDEPENDENT_CODE "Build with Position Independant Code." ON)
endif()

Can we provide two structures with bit-fields and without for shared lib?

#if define(CPU_FEATURES_SHARED_LIB) && defined(CPU_FEATURES_SHARED_LIB_EXPORT)
typedef struct {
  int msa;   // MIPS SIMD Architecture
                // https://www.mips.com/products/architectures/ase/simd/
  int eva;  // Enhanced Virtual Addressing
                // https://www.mips.com/products/architectures/mips64/
  int r6;   // True if is release 6 of the processor.

  // Make sure to update MipsFeaturesEnum below if you add a field here.
} MipsFeatures;
#else
typedef struct {
  int msa : 1;  // MIPS SIMD Architecture
                // https://www.mips.com/products/architectures/ase/simd/
  int eva : 1;  // Enhanced Virtual Addressing
                // https://www.mips.com/products/architectures/mips64/
  int r6 : 1;   // True if is release 6 of the processor.

  // Make sure to update MipsFeaturesEnum below if you add a field here.
} MipsFeatures;
#endif

or we can do it via bit operations, but this approach is too complicated and requires a lot of work:

typedef struct {
   int record;
} MipsFeatures;

#define CPU_FEATURES_MIPS_MSA_FLAG_PRESENT  0x4

int GetFlagMsa(const MipsFeatures* mipsFeatures) {
  return IsBitSet(mipsFeatures->record, 3);
}

void SetFlagMsa(const MipsFeatures* mipsFeatures) {
  mipsFeatures->record |= CPU_FEATURES_MIPS_MSA_FLAG_PRESENT;
}

void ClearFlagMsa(const MipsFeatures* mipsFeatures) {
  mipsFeatures->record &= ~CPU_FEATURES_MIPS_MSA_FLAG_PRESENT;
}

@gchatelet, @Mizux, what do you think?

@gchatelet
Copy link
Collaborator

It would be great to improve the public API for porting the library.

Are you talking about porting the library to different languages? Which ones?

however we have one point with shared library

Not only there's a potential issue with bitfields but we are also not providing any ABI stability guarantees.
That's why we strongly discourage the use of shared libraries.

When this project was created, the vision was that it could be run on embedded devices with small memory footprint - hence C99 and bitfields.

I'm not fond of the #ifdef/#endif solution which duplicates the code and is bound to diverge over time. Also it makes the header file harder to understand.


Now if we want to port the API to higher level languages (C#, Java, Python, Go) I think we can trade performance and use the reflection API instead. This should already work out of the box for features in the following (admittedly ugly) way:

  • walk GetX86FeaturesEnumName() by using an incrementing number from 0 up until you get "unknown_feature".
  • then you can query all features from 0 to the number you found with GetX86FeaturesEnumValue() which returns a non-0 or 0 value depending on if it's set or not.

Solution 1, a real API

It is not nice but I believe we can create a nicer API on top of that that abstracts cpu away completely. e.g.

int GetLastFeatureEnum();
int GetFeaturesEnumValue(int);
const char* GetFeaturesEnumString(int);

Solution 2, parsing JSON

Another option that requires much less work is to have the host language run list_cpu_features --json and parse its output (or provide a library function to prevent the overhead of creating a process, something like const char* GetJsonCpuInfo()).
If we choose this option then we need to properly define the content of the JSON output and make it stable over time.

What do you think?

@gchatelet gchatelet added the enhancement New feature or request label Jan 24, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants