Skip to content

64-bit integer metrics sometimes incorrect in the Run Explorer UI and exported CSVs #3409

Description

@asunderwood

🐛 Bug

64-bit int metrics report incorrectly in the Runs Explorer table if the 31st bit in the value is set. This causes the UI to report an incorrect metric while the metrics graphs and the Aim repo itself will report the correct value. Because the export function in the Runs Explorer view uses the same data from that table, the exported CSVs also contain incorrect values.

To reproduce

Click for reprex code
import os
from aim import Repo, Run

# byte 3 = 0x3B, high bit clear -> displays correctly as 1,000,000,000
GOOD_VALUE = 1_000_000_000

# byte 3 = 0xB2, high bit SET -> UI displays -1,294,967,296 (off by 2^32 -> negative)
BAD_VALUE = 3_000_000_000

repo_path = os.path.dirname(os.path.abspath(__file__))
Repo(repo_path, init=True)

run = Run(repo=repo_path, experiment='int64-decoder-bug-demo')
run.name = 'int64-decoder-bug-demo'

run.track(GOOD_VALUE, name='good_int64', step=0)
run.track(BAD_VALUE, name='bad_int64', step=0)
run.close()

byte3_good = (GOOD_VALUE >> 24) & 0xFF
byte3_bad = (BAD_VALUE >> 24) & 0xFF
print(f'Run hash: {run.hash}')
print(f'good_int64: tracked {GOOD_VALUE:,}'
      f' (byte3=0x{byte3_good:02X}, high bit {"set" if byte3_good & 0x80 else "clear"})'
      f' -> UI shows {GOOD_VALUE:,}')
print(f'bad_int64:  tracked {BAD_VALUE:,}'
      f' (byte3=0x{byte3_bad:02X}, high bit {"set" if byte3_bad & 0x80 else "clear"})'
      f' -> UI shows {BAD_VALUE - 2**32:,}')

This code will create a new Aim repo in the current directory, register a new run, and add 2 values which should showcase the issue.

In this demo case, I intentionally picked a value to show negative in the UI which is rather extreme and would instantly tip a user off to problems. But I actually encountered this in the wild with a much larger value where the bugged value was also reasonable. It wasn't until pouring over charts I noticed the discrepancy, so this can sneak up on you.

Expected behavior

bad_int64 value in the Runs Explorer table should show 3,000,000,000, not a negative number. Additionally, the exported CSV from the Runs Explorer should export the correct 3,000,000,000 value and not the negative.

Environment

  • Aim Version - 3.29.1
  • Python version - 3.12.13
  • pip version - 26.0.1
  • OS
    • Aim server: Ubuntu 24.04
    • UI client: Windows 11 Build 26200
  • Browsers tested:
    • Microsoft Edge 148.0.3967.54
    • Google Chrome 147.0.7778.98

Additional context

I believe the issue is in this section of code here:

return (
x[offset + 7] * _2__56 +
x[offset + 6] * _2__48 +
x[offset + 5] * _2__40 +
x[offset + 4] * _2__32 +
(x[offset + 3] << 24) +
(x[offset + 2] << 16) +
(x[offset + 1] << 8) +
(x[offset + 0] << 0)
);
}

The << in JavaScript is treating the output as a signed 32-bit int and therefore the 3rd byte becomes negative with the most significant bit of the 3rd byte (31st bit of the entire 64-bit value) is set.

Following the conventions around that code, a new const _2__24 = Math.pow(2, 24); followed by x[offset + 3] * _2__24 + for that 3rd byte should fix it?

Metadata

Metadata

Assignees

No one assigned

    Labels

    help wantedExtra attention is neededtype / bugIssue type: something isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions