@@ -2175,40 +2175,26 @@ def test_get_stats_l1():
21752175 cufile .write (handle , buf_ptr_int , buffer_size , 0 , 0 )
21762176 cufile .read (handle , buf_ptr_int , buffer_size , 0 , 0 )
21772177
2178- # Allocate buffer for L1 statistics
2179- stats_buffer = ctypes .create_string_buffer (1024 ) # Allocate sufficient space
2180- stats_ptr = ctypes .addressof (stats_buffer )
2181-
2178+ # Use the exposed StatsLevel1 class from cufile module
2179+ stats = cufile .StatsLevel1 ()
2180+
21822181 # Get L1 statistics (basic operation counts)
2183- cufile .get_stats_l1 (stats_ptr )
2184-
2185- # Define ctypes structure matching CUfileStatsLevel1_t
2186- class OpCounter (ctypes .Structure ):
2187- _fields_ = [("ok" , ctypes .c_uint64 ), ("err" , ctypes .c_uint64 )]
2188-
2189- class StatsL1 (ctypes .Structure ):
2190- _fields_ = [
2191- ("read_ops" , OpCounter ), ("write_ops" , OpCounter ),
2192- ("hdl_register_ops" , OpCounter ), ("hdl_deregister_ops" , OpCounter ),
2193- ("buf_register_ops" , OpCounter ), ("buf_deregister_ops" , OpCounter ),
2194- ("read_bytes" , ctypes .c_uint64 ), ("write_bytes" , ctypes .c_uint64 ),
2195- ("read_bw_bytes_per_sec" , ctypes .c_uint64 ), ("write_bw_bytes_per_sec" , ctypes .c_uint64 ),
2196- ("read_lat_avg_us" , ctypes .c_uint64 ), ("write_lat_avg_us" , ctypes .c_uint64 ),
2197- ("read_ops_per_sec" , ctypes .c_uint64 ), ("write_ops_per_sec" , ctypes .c_uint64 ),
2198- ("read_lat_sum_us" , ctypes .c_uint64 ), ("write_lat_sum_us" , ctypes .c_uint64 ),
2199- ]
2200-
2201- # Cast buffer to structure and examine fields
2202- stats = ctypes .cast (stats_ptr , ctypes .POINTER (StatsL1 )).contents
2182+ cufile .get_stats_l1 (stats .ptr )
22032183
22042184 # Verify actual field values
2205- assert stats .read_ops .ok > 0 , f"Expected read operations, got { stats .read_ops .ok } "
2206- assert stats .write_ops .ok > 0 , f"Expected write operations, got { stats .write_ops .ok } "
2207- assert stats .read_bytes > 0 , f"Expected read bytes, got { stats .read_bytes } "
2208- assert stats .write_bytes > 0 , f"Expected write bytes, got { stats .write_bytes } "
2209-
2210- logging .info (f"Stats: reads={ stats .read_ops .ok } , writes={ stats .write_ops .ok } , "
2211- f"read_bytes={ stats .read_bytes } , write_bytes={ stats .write_bytes } " )
2185+ # Access numpy recarray fields: read_ops returns a recarray with 'ok' and 'err' fields
2186+ read_ops_ok = int (stats .read_ops ['ok' ][0 ])
2187+ write_ops_ok = int (stats .write_ops ['ok' ][0 ])
2188+ read_bytes = int (stats .read_bytes )
2189+ write_bytes = int (stats .write_bytes )
2190+
2191+ assert read_ops_ok > 0 , f"Expected read operations, got { read_ops_ok } "
2192+ assert write_ops_ok > 0 , f"Expected write operations, got { write_ops_ok } "
2193+ assert read_bytes > 0 , f"Expected read bytes, got { read_bytes } "
2194+ assert write_bytes > 0 , f"Expected write bytes, got { write_bytes } "
2195+
2196+ logging .info (f"Stats: reads={ read_ops_ok } , writes={ write_ops_ok } , "
2197+ f"read_bytes={ read_bytes } , write_bytes={ write_bytes } " )
22122198
22132199 # Stop statistics collection
22142200 cufile .stats_stop ()
@@ -2286,27 +2272,16 @@ def test_get_stats_l2():
22862272 cufile .write (handle , buf_ptr_int , buffer_size , buffer_size , 0 ) # Different offset
22872273 cufile .read (handle , buf_ptr_int , buffer_size , buffer_size , 0 )
22882274
2289- # Allocate buffer for L2 statistics
2290- stats_buffer = ctypes .create_string_buffer (2048 ) # Larger buffer for detailed stats
2291- stats_ptr = ctypes .addressof (stats_buffer )
2275+ # Use the exposed StatsLevel2 class from cufile module
2276+ stats = cufile .StatsLevel2 ()
22922277
22932278 # Get L2 statistics (detailed performance metrics)
2294- cufile .get_stats_l2 (stats_ptr )
2295-
2296- # Define ctypes structure matching CUfileStatsLevel2_t
2297- class StatsL2 (ctypes .Structure ):
2298- _fields_ = [
2299- ("basic" , ctypes .c_byte * 512 ), # L1 data (simplified)
2300- ("read_size_kb_hist" , ctypes .c_uint64 * 32 ),
2301- ("write_size_kb_hist" , ctypes .c_uint64 * 32 ),
2302- ]
2303-
2304- # Cast buffer to structure and examine L2-specific fields
2305- stats = ctypes .cast (stats_ptr , ctypes .POINTER (StatsL2 )).contents
2279+ cufile .get_stats_l2 (stats .ptr )
23062280
23072281 # Verify L2 histogram fields contain data
2308- read_hist_total = sum (stats .read_size_kb_hist )
2309- write_hist_total = sum (stats .write_size_kb_hist )
2282+ # Access numpy array fields: histograms are numpy arrays
2283+ read_hist_total = int (stats .read_size_kb_hist .sum ())
2284+ write_hist_total = int (stats .write_size_kb_hist .sum ())
23102285 assert read_hist_total > 0 or write_hist_total > 0 , "Expected L2 histogram data"
23112286
23122287 logging .info (f"L2 Stats: read_hist_total={ read_hist_total } , write_hist_total={ write_hist_total } " )
@@ -2391,49 +2366,27 @@ def test_get_stats_l3():
23912366 cufile .write (handle , buf_ptr_int , buffer_size // 2 , buffer_size * 2 , 0 ) # Partial write
23922367 cufile .read (handle , buf_ptr_int , buffer_size // 2 , buffer_size * 2 , 0 ) # Partial read
23932368
2394- # Allocate buffer for L3 statistics
2395- stats_buffer = ctypes .create_string_buffer (4096 ) # Largest buffer for comprehensive stats
2396- stats_ptr = ctypes .addressof (stats_buffer )
2369+ # Use the exposed StatsLevel3 class from cufile module
2370+ stats = cufile .StatsLevel3 ()
23972371
23982372 # Get L3 statistics (comprehensive diagnostic data)
2399- cufile .get_stats_l3 (stats_ptr )
2400-
2401- # Define ctypes structure matching CUfileStatsLevel3_t
2402- class PerGpuStats (ctypes .Structure ):
2403- _fields_ = [
2404- ("uuid" , ctypes .c_char * 16 ),
2405- ("read_bytes" , ctypes .c_uint64 ),
2406- ("read_bw_bytes_per_sec" , ctypes .c_uint64 ),
2407- ("read_utilization" , ctypes .c_uint64 ),
2408- ("read_duration_us" , ctypes .c_uint64 ),
2409- ("n_total_reads" , ctypes .c_uint64 ),
2410- ("n_p2p_reads" , ctypes .c_uint64 ),
2411- ("n_nvfs_reads" , ctypes .c_uint64 ),
2412- ("n_posix_reads" , ctypes .c_uint64 ),
2413- ]
2414-
2415- class StatsL3 (ctypes .Structure ):
2416- _fields_ = [
2417- ("detailed" , ctypes .c_byte * 2048 ), # L2 data (simplified)
2418- ("num_gpus" , ctypes .c_uint32 ),
2419- ("per_gpu_stats" , PerGpuStats * 16 ),
2420- ]
2421-
2422- # Cast buffer to structure and examine L3-specific fields
2423- stats = ctypes .cast (stats_ptr , ctypes .POINTER (StatsL3 )).contents
2373+ cufile .get_stats_l3 (stats .ptr )
24242374
24252375 # Verify L3-specific fields
2426- assert stats .num_gpus >= 0 , f"Expected valid GPU count, got { stats .num_gpus } "
2376+ num_gpus = int (stats .num_gpus )
2377+ assert num_gpus >= 0 , f"Expected valid GPU count, got { num_gpus } "
24272378
24282379 # Check if we have at least one GPU with stats
2380+ # per_gpu_stats is a numpy recarray with shape (16,)
24292381 gpu_with_data = False
2430- for i in range (min (stats . num_gpus , 16 )):
2382+ for i in range (min (num_gpus , 16 )):
24312383 gpu_stats = stats .per_gpu_stats [i ]
2432- if gpu_stats .n_total_reads > 0 or gpu_stats .read_bytes > 0 :
2384+ # Access scalar values from the recarray element
2385+ if int (gpu_stats ['n_total_reads' ][0 ]) > 0 or int (gpu_stats ['read_bytes' ][0 ]) > 0 :
24332386 gpu_with_data = True
24342387 break
24352388
2436- logging .info (f"L3 Stats: num_gpus={ stats . num_gpus } , gpu_with_data={ gpu_with_data } " )
2389+ logging .info (f"L3 Stats: num_gpus={ num_gpus } , gpu_with_data={ gpu_with_data } " )
24372390
24382391 # Stop statistics collection
24392392 cufile .stats_stop ()
0 commit comments