Skip to content

Add test for number of threads of OpenBLAS - #3293

Open
filikat wants to merge 9 commits into
latestfrom
openblas-test
Open

filikat wants to merge 9 commits into
latestfrom
openblas-test

Conversation

@filikat

@filikat filikat commented Sep 16, 2026

Copy link
Copy Markdown
Collaborator

Description

  • Add openblas_get_num_threads, to query the number of threads used by OpenBLAS.
  • After setting the number of threads for OpenBLAS to 1, check that indeed OpenBLAS is using 1 thread. This may catch errors in how the flag HIPO_USES_OPENBLAS is passed to HiPO.
  • If BLAS_LIBRARIES is used and the provided library contains the string openblas, set the BLAS metadata so that HiPO knows that OpenBLAS is being used.

Checklist

  • I have read the contributing guidelines
  • This PR targets the latest branch
  • Tests are passing
  • Documentation was updated where relevant
  • This PR is not primarily AI-generated (per the AI contributions policy in CONTRIBUTING.md)

@filikat filikat self-assigned this Sep 16, 2026
@filikat filikat added the HiPO label Sep 16, 2026
@codecov

codecov Bot commented Sep 16, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 20 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.56%. Comparing base (c9e05bc) to head (e44f9fe).
⚠️ Report is 69 commits behind head on latest.

Files with missing lines Patch % Lines
highs/ipm/IpxWrapper.cpp 0.00% 14 Missing ⚠️
highs/ipm/hipo/ipm/FactorHighsSolver.cpp 0.00% 4 Missing ⚠️
extern/HighsExtrasExternalDeps.h 0.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           latest    #3293      +/-   ##
==========================================
+ Coverage   73.31%   73.56%   +0.24%     
==========================================
  Files         446      446              
  Lines      108397   109543    +1146     
  Branches    17360    17547     +187     
==========================================
+ Hits        79476    80588    +1112     
- Misses      28645    28678      +33     
- Partials      276      277       +1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@mathgeekcoder mathgeekcoder left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quick question: are you wanting to use openblas_get_num_threads for anything else?

An alternate implementation would be to modify the set_num_threads to also return the number of threads:

int openblas_set_num_threads(int num_threads) {
#if defined(HIPO_USES_OPENBLAS)
  openblas_set_num_threads(num_threads);
  return openblas_get_num_threads();
#else
  return num_threads;
#endif
}

This would make most of the other changes unnecessary.

@filikat

filikat commented Sep 17, 2026

Copy link
Copy Markdown
Collaborator Author

openblas_get_num_threads is not used anywhere else at the moment, so I can remove it and follow your suggestion. I would still leave the check of whether the BLAS provider and HIPO_USES_OPENBLAS agree. If OpenBLAS is used, but HIPO_USES_OPENBLAS is not set, the performance deteriorates considerably because the number of threads is not set to 1. These changes are meant to guarantee that it doesn't happen.

@mathgeekcoder mathgeekcoder left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking better! I've added a couple more optional suggestions


static bool usingAppleBlas() {
return strstr(HighsExtras::blas::getInfo()->provider, "Apple") != nullptr;
std::string provider = HighsExtras::blas::getInfo()->provider;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we can include something like this in stringutil.h?

#if defined(_WIN32) || defined(_WIN64)
#include <string.h>  // _stricmp
#else
#include <strings.h>  // strcasecmp
#endif

inline int stringcasecmp(const char* lhs, const char* rhs) {
#if defined(_WIN32) || defined(_WIN64)
  return _stricmp(lhs, rhs);
#else
  return strcasecmp(lhs, rhs);
#endif
}

Then this becomes:

static bool usingAppleBlas() {
   return stringcasecmp(HighsExtras::blas::getInfo()->provider, "apple") == 0;
}

It should be faster and cleaner than creating a string, converting to lower and comparing.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively, we could modify HighsExtrasFeatureInfo:

bool HighsExtrasFeatureInfo::isProvider(const char* check) {
   return stringcasecmp(provider, check) == 0;
}

such that:

HighsExtras::blas::getInfo()->isProvider("apple");

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this looks neat, I will make the changes

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to check for substrings, not exact match though (so that "Apple Accelerate" matches "apple"). I replaced strcasecmp with strcasestr. Unfortunately there seems to be no equivalent on Windows. One possible solution is to use _strnicmp iteratively. I am not sure of whether this is fast, but it shouldn't be a big deal. The providers are short and need to be checked only a couple of times.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm having some issues to include stringutil.h in HighsExtrasApiBinding.h in a way that works everywhere, in order to implement isProvider. I will remove isProvider for now.

Comment thread highs/ipm/IpxWrapper.cpp Outdated
}

static bool usingOpenBLAS() {
std::string provider = HighsExtras::blas::getInfo()->provider;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above

static bool usingOpenBLAS() {
   return stringcasecmp(HighsExtras::blas::getInfo()->provider, "openblas") == 0;
}

Comment thread cmake/FindHipoDeps.cmake
function(highs_configure_blas_metadata)
set(HIGHS_BLAS_COMPILE_DEFINITION "" PARENT_SCOPE)

string(TOLOWER "${BLAS_LIBRARIES}" BLAS_LIBRARIES_LOWER)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, can you explain why this is needed?

@filikat filikat Sep 19, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I use OpenBLAS by passing libopenblas.so to BLAS_LIBRARIES, CMake doesn't know which vendor is being used and so it doesn't set the BLAS metadata (i.e., the provider is unknown, etc). Crucially, this means that HIPO_USES_OPENBLAS is not set, and OpenBLAS runs multi-threaded, with a substantial reduction in performance.
Maybe there are better ways of achieving this.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants