Skip to content

Regression testing / Reproducability: Fix MacOS and Linux differences for rand() and qsort()#9574

Closed
fredowski wants to merge 6 commits into
The-OpenROAD-Project:masterfrom
fredowski:randfix
Closed

Regression testing / Reproducability: Fix MacOS and Linux differences for rand() and qsort()#9574
fredowski wants to merge 6 commits into
The-OpenROAD-Project:masterfrom
fredowski:randfix

Conversation

@fredowski

Copy link
Copy Markdown
Contributor

As already discussed in #9480 the regression yields different results on MacOS and on Linux. Today around 60 tests fail on MacOS when running a part of the regression in bazel with

bazelisk test src/...

One major reason are different implementations of rand() and qsort() between glibc and the apple functions. qsort() gives different results for equal elements. This PR addresses this problem by

  • Change the rand function in gpl to mt19937 which yields the same pseudorandom sequences on apple and linux
  • Update the new "golden" reference files due to this change
  • Provide a copy of rand() and qsort() for apple which is copied from glibc and link this to the abc code. This avoids to change abc. This update does not need an update of the "golden" reference files as they are produces on linux anyway.

I tested this on MacOS and debian 12 x86_64. On MacOS the failed tests are reduced to 5. On linux x86_64 there are no regression failures.

I think these changes have no impact on actual function but only on regression and reproducability. You can see the small differences in the updated golden files.

rand() produces different sequences on glibc from linux
versus Apple libc. mt19937 produces the same sequence
on all platforms. This affects 26 tests in gpl and 3 tests
in rsz plus the python tests which test the same.
This reduces the regression test failures on MacOS from
60 to 11.

Signed-off-by: Friedrich Beckmann <friedrich.beckmann@tha.de>
The new platform deterministic mt19937 random number
generator produces new reference files. This commit
contains the updated golden reference files.

Signed-off-by: Friedrich Beckmann <friedrich.beckmann@tha.de>
abc uses rand() in various places. The glibc version and the
apple version of rand() produce different sequences. This
produces different results on MacOS and Linux. This
patch provides rand() and qsort() for the MacOS build to
achieve the same results. As this version mirrors the
glibc behaviour, the golden regression files can remain
untouched. This reduces the regression failures from 11
to 4 - mainly for rmp module tests.

Signed-off-by: Friedrich Beckmann <friedrich.beckmann@tha.de>
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Note

The number of changes in this pull request is too large for Gemini Code Assist to generate a review.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

clang-tidy made some suggestions

There were too many comments to post at once. Showing the first 25 out of 29. Check the log or trigger a new build to see more.

* Simplified implementation of the merge sort algorithm used by glibc.
*/

#include <stdlib.h>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: inclusion of deprecated C++ header 'stdlib.h'; consider using 'cstdlib' instead [modernize-deprecated-headers]

Suggested change
#include <stdlib.h>
#include <cstdlib>

*/

#include <stdlib.h>
#include <string.h>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: inclusion of deprecated C++ header 'string.h'; consider using 'cstring' instead [modernize-deprecated-headers]

Suggested change
#include <string.h>
#include <cstring>

#include <string.h>

/* Threshold below which we use insertion sort */
#define INSERTION_THRESHOLD 4

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: macro 'INSERTION_THRESHOLD' defines an integral constant; prefer an enum instead [modernize-macro-to-enum]

#define INSERTION_THRESHOLD 4
        ^


/* Threshold below which we use insertion sort */
#define INSERTION_THRESHOLD 4

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: replace macro with enum [modernize-macro-to-enum]

Suggested change
enum {
INSERTION_THRESHOLD = 4};

Comment thread bazel/glibc_for_apple/portable_rand.c Outdated
* TYPE_3: degree 31, separation 3
*/

#define DEG_3 31

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: macro 'DEG_3' defines an integral constant; prefer an enum instead [modernize-macro-to-enum]

#define DEG_3  31
        ^

Comment thread bazel/glibc_for_apple/portable_rand.c Outdated
_init_state(seed);
}

int rand(void)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: function 'rand' can be made static or moved into an anonymous namespace to enforce internal linkage [misc-use-internal-linkage]

Suggested change
int rand(void)
static int rand(void)

Comment thread bazel/glibc_for_apple/portable_rand.c Outdated
_init_state(seed);
}

int rand(void)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: no header providing "rand" is directly included [misc-include-cleaner]

int rand(void)
    ^

Comment thread bazel/glibc_for_apple/portable_rand.c Outdated
_init_state(seed);
}

int rand(void)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: redundant void argument list in function definition [modernize-redundant-void-arg]

Suggested change
int rand(void)
int rand()

Comment thread bazel/glibc_for_apple/portable_rand.c Outdated
int rand(void)
{
if (!_initialized)
_init_state(1);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: statement should be inside braces [google-readability-braces-around-statements]

Suggested change
_init_state(1);
if (!_initialized) {
_init_state(1);
}

Comment thread bazel/glibc_for_apple/portable_rand.c Outdated
if (!_initialized)
_init_state(1);

unsigned int result = _state[_fptr] + _state[_rptr];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: no header providing "result" is directly included [misc-include-cleaner]

    unsigned int result = _state[_fptr] + _state[_rptr];
                 ^

…ange

Signed-off-by: Friedrich Beckmann <friedrich.beckmann@tha.de>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

clang-tidy made some suggestions

Comment thread bazel/glibc_for_apple/portable_rand.c Outdated
unsigned int result = _state[_fptr] + _state[_rptr];
_state[_fptr] = result;

int ret = (int)((result >> 1) & 0x7fffffffU);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: no header providing "ret" is directly included [misc-include-cleaner]

    int ret = (int)((result >> 1) & 0x7fffffffU);
        ^

Comment thread bazel/glibc_for_apple/portable_rand.c Outdated

_fptr++;
if (_fptr >= DEG_3)
_fptr = 0;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: statement should be inside braces [google-readability-braces-around-statements]

Suggested change
_fptr = 0;
if (_fptr >= DEG_3) {
_fptr = 0;
}

Comment thread bazel/glibc_for_apple/portable_rand.c Outdated
_fptr = 0;
_rptr++;
if (_rptr >= DEG_3)
_rptr = 0;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: statement should be inside braces [google-readability-braces-around-statements]

Suggested change
_rptr = 0;
if (_rptr >= DEG_3) {
_rptr = 0;
}

Comment thread bazel/glibc_for_apple/portable_rand.c Outdated
return ret;
}

int rand_r(unsigned int *seedp)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: function 'rand_r' can be made static or moved into an anonymous namespace to enforce internal linkage [misc-use-internal-linkage]

Suggested change
int rand_r(unsigned int *seedp)
static int rand_r(unsigned int *seedp)

I ran clang-tidy on the two new files. No functional change.

Signed-off-by: Friedrich Beckmann <friedrich.beckmann@tha.de>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

clang-tidy made some suggestions

There were too many comments to post at once. Showing the first 25 out of 29. Check the log or trigger a new build to see more.

char *b = (char *)base;
char *tmp = (char *)malloc(size);
if (!tmp)
return;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: statement should be inside braces [google-readability-braces-around-statements]

Suggested change
return;
if (!tmp) {
return;
}

dst += size;
}
if (n1 > 0)
memcpy(dst, src1, n1 * size);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: statement should be inside braces [google-readability-braces-around-statements]

Suggested change
memcpy(dst, src1, n1 * size);
if (n1 > 0) {
memcpy(dst, src1, n1 * size);
}

if (n1 > 0)
memcpy(dst, src1, n1 * size);
if (n2 > 0)
memcpy(dst, src2, n2 * size);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: statement should be inside braces [google-readability-braces-around-statements]

Suggested change
memcpy(dst, src2, n2 * size);
if (n2 > 0) {
memcpy(dst, src2, n2 * size);
}

void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *)) {
if (nmemb < 2)
return;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: statement should be inside braces [google-readability-braces-around-statements]

Suggested change
return;
if (nmemb < 2) {
return;
}

* TYPE_3: degree 31, separation 3
*/

#define DEG_3 31

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: macro 'DEG_3' defines an integral constant; prefer an enum instead [modernize-macro-to-enum]

#define DEG_3 31
        ^


void srand(unsigned int seed) { _init_state(seed); }

int rand(void) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: function 'rand' can be made static or moved into an anonymous namespace to enforce internal linkage [misc-use-internal-linkage]

Suggested change
int rand(void) {
static int rand(void) {


void srand(unsigned int seed) { _init_state(seed); }

int rand(void) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: no header providing "rand" is directly included [misc-include-cleaner]

int rand(void) {
    ^


void srand(unsigned int seed) { _init_state(seed); }

int rand(void) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: redundant void argument list in function definition [modernize-redundant-void-arg]

Suggested change
int rand(void) {
int rand() {


int rand(void) {
if (!_initialized)
_init_state(1);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: statement should be inside braces [google-readability-braces-around-statements]

Suggested change
_init_state(1);
if (!_initialized) {
_init_state(1);
}

if (!_initialized)
_init_state(1);

unsigned int result = _state[_fptr] + _state[_rptr];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: no header providing "result" is directly included [misc-include-cleaner]

  unsigned int result = _state[_fptr] + _state[_rptr];
               ^

Signed-off-by: Friedrich Beckmann <friedrich.beckmann@tha.de>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

clang-tidy made some suggestions

unsigned int result = _state[_fptr] + _state[_rptr];
_state[_fptr] = result;

int ret = (int)((result >> 1) & 0x7fffffffU);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: no header providing "ret" is directly included [misc-include-cleaner]

  int ret = (int)((result >> 1) & 0x7fffffffU);
      ^


_fptr++;
if (_fptr >= DEG_3)
_fptr = 0;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: statement should be inside braces [google-readability-braces-around-statements]

Suggested change
_fptr = 0;
if (_fptr >= DEG_3) {
_fptr = 0;
}

_fptr = 0;
_rptr++;
if (_rptr >= DEG_3)
_rptr = 0;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: statement should be inside braces [google-readability-braces-around-statements]

Suggested change
_rptr = 0;
if (_rptr >= DEG_3) {
_rptr = 0;
}

return ret;
}

int rand_r(unsigned int *seedp) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warning: function 'rand_r' can be made static or moved into an anonymous namespace to enforce internal linkage [misc-use-internal-linkage]

Suggested change
int rand_r(unsigned int *seedp) {
static int rand_r(unsigned int *seedp) {

@QuantamHD

Copy link
Copy Markdown
Collaborator

Instead of pulling LGPL code, could we just stub these function with the c++ version std::mt1997 etc. or std::stable_sort

@fredowski

Copy link
Copy Markdown
Contributor Author

Yes this exploded in clang-tidy, google code hints and friends. I will remove the last part with rand() and qsort() and just do a new pr.

@fredowski fredowski closed this Feb 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants