Skip to content

Commit

Permalink
TSDS: Revision of ThreadSafeDataStorage utility functions
Browse files Browse the repository at this point in the history
- cleaner API with public ReadVar / WriteVar and private Create / Storage Getter

- writing a variable now does not reinitializes the named storage causing an
  additional release of two waves and a recreation of two waves. Due to
  memory allocation each wave creation causes a global lock.

- fixes the mixed if check of data/wv in Line 63

- adapted tests
  • Loading branch information
MichaelHuth committed Sep 24, 2024
1 parent 831972d commit e28a73e
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 69 deletions.
2 changes: 1 addition & 1 deletion Packages/MIES/MIES_Debugging.ipf
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,7 @@ threadsafe Function BUG_TS(string msg, [WAVE/T keys, WAVE/T values])
TUFXOP_AcquireLock/N=(TSDS_BUGCOUNT)
bugCount = TSDS_ReadVar(TSDS_BUGCOUNT, defValue = 0, create = 1)
bugCount += 1
TSDS_Write(TSDS_BUGCOUNT, var = bugCount)
TSDS_WriteVar(TSDS_BUGCOUNT, bugCount)
TUFXOP_ReleaseLock/N=(TSDS_BUGCOUNT)

print "BUG_TS: Should never be called during automated testing."
Expand Down
73 changes: 42 additions & 31 deletions Packages/MIES/MIES_ThreadsafeDataSharing.ipf
Original file line number Diff line number Diff line change
Expand Up @@ -10,59 +10,70 @@
///
/// @brief Helper functions for accessing global objects from all threads

threadsafe Function TSDS_Write(string name, [variable var])
ASSERT_TS(!ParamIsDefault(var), "Missing var parameter")
/// @brief Creates/Overwrites a threadstorage and puts a numerical value in
threadsafe static Function TSDS_Create(string name, variable var)

ASSERT_TS(!IsEmpty(name), "name can not be empty")

TUFXOP_Init/N=name/Z
TUFXOP_GetStorage/N=name/Z wv
TUFXOP_Init/Z/N=name
TUFXOP_GetStorage/Z/N=name wv

Make/FREE/N=(1)/D data = var
Make/FREE/D data = {var}
wv[0] = data
End

/// @brief Reads a numerical value from a threadstorage
///
/// @param name name of threadstorage
/// @param defValue [optional: default NaN] default value used when storage is created, create flag must be set
/// @param create [optional: default 0] when set the threadstorage is created if it did not exist or had an incompatible format, defValue must be given
threadsafe Function TSDS_ReadVar(string name, [variable defValue, variable create])

variable argCheck = ParamIsDefault(defValue) + ParamIsDefault(create)
ASSERT_TS(argCheck == 2 || argCheck == 0, "defaul value and create must be either both set or both default.")
ASSERT_TS(!IsEmpty(name), "name can not be empty")

if(ParamIsDefault(defValue))
defValue = NaN
endif

if(ParamIsDefault(create))
create = 0
else
create = !!create
endif
defValue = ParamIsDefault(defValue) ? NaN : defValue
create = ParamIsDefault(create) ? 0 : !!create

WAVE/Z data = TSDS_Read(name)
if(WaveExists(data) && IsNumericWave(data) && DimSize(data, ROWS) == 1)
return data[0]
endif

if(!WaveExists(data))
if(create)
TSDS_Write(name, var = defValue)
endif
ASSERT_TS(create == 1, "Error reading from threadstorage:" + name)

return defValue
endif
TSDS_Create(name, defValue)

return data[0]
return defValue
End

/// @brief Reads a single wave ref wave from a named threadstorage
threadsafe static Function/WAVE TSDS_Read(string name)
TUFXOP_GetStorage/Q/N=name/Z wv

if(V_flag)
return $""
TUFXOP_GetStorage/Q/N=name/Z wv
if(!V_flag && WaveExists(wv) && IsWaveRefWave(wv) && DimSize(wv, ROWS) == 1)
return wv[0]
endif

if(!WaveExists(wv) || !IsWaveRefWave(wv) || DimSize(wv, ROWS) != 1)
return $""
endif
return $""
End

/// @brief Writes a numerical value to a threadstorage, if the threadstorage does not exist it is automatically created.
///
/// @param name name of threadstorage
/// @param var numerical value that should be written
/// @returns 0 if write was successful, 1 if write was not successful
threadsafe Function TSDS_WriteVar(string name, variable var)

ASSERT_TS(!IsEmpty(name), "name can not be empty")

WAVE/Z data = wv[0]
WAVE/Z data = TSDS_Read(name)
if(WaveExists(data) && IsNumericWave(data) && DimSize(data, ROWS) == 1)
data[0] = var

if(!WaveExists(data) || !IsNumericWave(data) || DimSize(wv, ROWS) != 1)
return $""
return NaN
endif

return data
TSDS_Create(name, var)
End
6 changes: 0 additions & 6 deletions Packages/tests/Basic/UTF_Debugging.ipf
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,6 @@ Function BUG_TSWorks1()

TUFXOP_Clear/N=(TSDS_BUGCOUNT)/Q/Z

bugCount = TSDS_ReadVar(TSDS_BUGCOUNT)
CHECK_EQUAL_VAR(bugCount, NaN)

BUG_TS("abcd")

bugCount = TSDS_ReadVar(TSDS_BUGCOUNT)
Expand All @@ -49,9 +46,6 @@ Function BUG_TSWorks2()

TUFXOP_Clear/N=(TSDS_BUGCOUNT)/Q/Z

bugCount = TSDS_ReadVar(TSDS_BUGCOUNT)
CHECK_EQUAL_VAR(bugCount, NaN)

numThreads = 10

Make/FREE/N=(numThreads) junk = NaN
Expand Down
60 changes: 32 additions & 28 deletions Packages/tests/Basic/UTF_ThreadsafeDataSharing.ipf
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,7 @@ End
static Function ChecksParams()

try
TSDS_Write(KEY)
FAIL()
catch
PASS()
endtry

try
TSDS_Write("", var = 1)
TSDS_WriteVar("", 1)
FAIL()
catch
PASS()
Expand All @@ -46,36 +39,39 @@ End
static Function WriteWorks1()
variable var

TSDS_Write(KEY, var = 123)
TSDS_WriteVar(KEY, 123)
var = TSDS_ReadVar(KEY)
CHECK_EQUAL_VAR(var, 123)

TSDS_Write(KEY, var = 567)
TSDS_WriteVar(KEY, 567)
var = TSDS_ReadVar(KEY)
CHECK_EQUAL_VAR(var, 567)
End

static Function ReadWorks1()
variable var

var = TSDS_ReadVar(KEY)
CHECK_EQUAL_VAR(var, NaN)
try
TSDS_ReadVar(KEY)
FAIL()
catch
PASS()
endtry

TSDS_Write(KEY, var = 123)
TSDS_WriteVar(KEY, 123)

var = TSDS_ReadVar(KEY)
CHECK_EQUAL_VAR(var, 123)
End

static Function ReadWorksWithDefault()
variable var

var = TSDS_ReadVar(KEY, defValue = 567)
CHECK_EQUAL_VAR(var, 567)

// but it is still not created
var = TSDS_ReadVar(KEY)
CHECK_EQUAL_VAR(var, NaN)
try
TSDS_ReadVar(KEY, defValue = 567)
FAIL()
catch
PASS()
endtry
End

static Function ReadWorksWithDefaultAndCreate()
Expand All @@ -92,31 +88,39 @@ End
static Function ReadBrokenStorage1()
variable var

var = TSDS_ReadVar(KEY, create = 1)
CHECK_EQUAL_VAR(var, NaN)
var = TSDS_ReadVar(KEY, defValue = 0, create = 1)
CHECK_EQUAL_VAR(var, 0)

// top level has the wrong size
TUFXOP_GetStorage/N=KEY wv
CHECK_WAVE(wv, WAVE_WAVE)

Redimension/N=0 wv

var = TSDS_ReadVar(KEY)
CHECK_EQUAL_VAR(var, NaN)
try
TSDS_ReadVar(KEY)
FAIL()
catch
PASS()
endtry
End

static Function ReadBrokenStorage2()
variable var

var = TSDS_ReadVar(KEY, create = 1)
CHECK_EQUAL_VAR(var, NaN)
var = TSDS_ReadVar(KEY, defValue = 0, create = 1)
CHECK_EQUAL_VAR(var, 0)

// contained wave is null
TUFXOP_GetStorage/N=KEY wv
CHECK_WAVE(wv, WAVE_WAVE)

wv[0] = $""

var = TSDS_ReadVar(KEY)
CHECK_EQUAL_VAR(var, NaN)
try
TSDS_ReadVar(KEY)
FAIL()
catch
PASS()
endtry
End
6 changes: 3 additions & 3 deletions Packages/tests/UTF_HelperFunctions.ipf
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ Function AdditionalExperimentCleanup()
KillVariables bugCount

TUFXOP_AcquireLock/N=(TSDS_BUGCOUNT)
TSDS_Write(TSDS_BUGCOUNT, var = 0)
TSDS_WriteVar(TSDS_BUGCOUNT, 0)
TUFXOP_ReleaseLock/N=(TSDS_BUGCOUNT)

KillOrMoveToTrash(wv = GetOverrideResults())
Expand Down Expand Up @@ -858,7 +858,7 @@ Function CheckForBugMessages()
endif

TUFXOP_AcquireLock/N=(TSDS_BUGCOUNT)
bugCount_ts = TSDS_ReadVar(TSDS_BUGCOUNT, defValue = 0)
bugCount_ts = TSDS_ReadVar(TSDS_BUGCOUNT, defValue = 0, create = 1)
TUFXOP_ReleaseLock/N=(TSDS_BUGCOUNT)

if(IsFinite(bugCount_ts))
Expand All @@ -873,7 +873,7 @@ Function DisableBugChecks()
NVAR bugCount = $GetBugCount()
bugCount = NaN

TSDS_Write(TSDS_BUGCOUNT, var = NaN)
TSDS_WriteVar(TSDS_BUGCOUNT, NaN)
End

/// @brief Exhaust all memory so that only `amountOfFreeMemoryLeft` [GB] is left
Expand Down

0 comments on commit e28a73e

Please sign in to comment.