2024-04-28 20:38:03 +03:00
/*
This file contains utilities shared between the different training scripts .
In particular , we define a series of macros xxxCheck that call the corresponding
C standard library function and check its return code . If an error was reported ,
the program prints some debug information and exits .
*/
2024-04-29 19:54:18 +00:00
# ifndef UTILS_H
# define UTILS_H
2024-04-28 20:38:03 +03:00
# include <stdio.h>
# include <stdlib.h>
2024-05-30 19:39:29 +00:00
# include <sys/stat.h>
// implementation of dirent for Windows is in dev/unistd.h
# ifndef _WIN32
# include <dirent.h>
# endif
2024-04-28 20:38:03 +03:00
// ----------------------------------------------------------------------------
// fread convenience utils, with nice handling of error checking using macros
// simple replace fopen, fread, fclose, fseek
// with fopenCheck, freadCheck, fcloseCheck, fseekCheck
FILE * fopen_check ( const char * path , const char * mode , const char * file , int line ) {
FILE * fp = fopen ( path , mode ) ;
if ( fp = = NULL ) {
fprintf ( stderr , " Error: Failed to open file '%s' at %s:%d \n " , path , file , line ) ;
fprintf ( stderr , " Error details: \n " ) ;
fprintf ( stderr , " File: %s \n " , file ) ;
fprintf ( stderr , " Line: %d \n " , line ) ;
fprintf ( stderr , " Path: %s \n " , path ) ;
fprintf ( stderr , " Mode: %s \n " , mode ) ;
2024-05-20 23:02:41 +00:00
fprintf ( stderr , " ---> HINT 1: dataset files/code have moved to dev/data recently (May 20, 2024). You may have to mv them from the legacy data/ dir to dev/data/(dataset), or re-run the data preprocessing script. Refer back to the main README \n " ) ;
fprintf ( stderr , " ---> HINT 2: possibly try to re-run `python train_gpt2.py` \n " ) ;
2024-04-28 20:38:03 +03:00
exit ( EXIT_FAILURE ) ;
}
return fp ;
}
# define fopenCheck(path, mode) fopen_check(path, mode, __FILE__, __LINE__)
void fread_check ( void * ptr , size_t size , size_t nmemb , FILE * stream , const char * file , int line ) {
size_t result = fread ( ptr , size , nmemb , stream ) ;
if ( result ! = nmemb ) {
if ( feof ( stream ) ) {
fprintf ( stderr , " Error: Unexpected end of file at %s:%d \n " , file , line ) ;
} else if ( ferror ( stream ) ) {
fprintf ( stderr , " Error: File read error at %s:%d \n " , file , line ) ;
} else {
fprintf ( stderr , " Error: Partial read at %s:%d. Expected %zu elements, read %zu \n " ,
file , line , nmemb , result ) ;
}
fprintf ( stderr , " Error details: \n " ) ;
fprintf ( stderr , " File: %s \n " , file ) ;
fprintf ( stderr , " Line: %d \n " , line ) ;
fprintf ( stderr , " Expected elements: %zu \n " , nmemb ) ;
fprintf ( stderr , " Read elements: %zu \n " , result ) ;
exit ( EXIT_FAILURE ) ;
}
}
# define freadCheck(ptr, size, nmemb, stream) fread_check(ptr, size, nmemb, stream, __FILE__, __LINE__)
void fclose_check ( FILE * fp , const char * file , int line ) {
if ( fclose ( fp ) ! = 0 ) {
fprintf ( stderr , " Error: Failed to close file at %s:%d \n " , file , line ) ;
fprintf ( stderr , " Error details: \n " ) ;
fprintf ( stderr , " File: %s \n " , file ) ;
fprintf ( stderr , " Line: %d \n " , line ) ;
exit ( EXIT_FAILURE ) ;
}
}
# define fcloseCheck(fp) fclose_check(fp, __FILE__, __LINE__)
void fseek_check ( FILE * fp , long off , int whence , const char * file , int line ) {
if ( fseek ( fp , off , whence ) ! = 0 ) {
fprintf ( stderr , " Error: Failed to seek in file at %s:%d \n " , file , line ) ;
fprintf ( stderr , " Error details: \n " ) ;
fprintf ( stderr , " Offset: %ld \n " , off ) ;
fprintf ( stderr , " Whence: %d \n " , whence ) ;
fprintf ( stderr , " File: %s \n " , file ) ;
fprintf ( stderr , " Line: %d \n " , line ) ;
exit ( EXIT_FAILURE ) ;
}
}
# define fseekCheck(fp, off, whence) fseek_check(fp, off, whence, __FILE__, __LINE__)
// ----------------------------------------------------------------------------
// malloc error-handling wrapper util
void * malloc_check ( size_t size , const char * file , int line ) {
void * ptr = malloc ( size ) ;
if ( ptr = = NULL ) {
fprintf ( stderr , " Error: Memory allocation failed at %s:%d \n " , file , line ) ;
fprintf ( stderr , " Error details: \n " ) ;
fprintf ( stderr , " File: %s \n " , file ) ;
fprintf ( stderr , " Line: %d \n " , line ) ;
fprintf ( stderr , " Size: %zu bytes \n " , size ) ;
exit ( EXIT_FAILURE ) ;
}
return ptr ;
}
2024-04-29 19:54:18 +00:00
# define mallocCheck(size) malloc_check(size, __FILE__, __LINE__)
2024-05-30 19:39:29 +00:00
// ----------------------------------------------------------------------------
// I/O ops
void create_dir_if_not_exists ( const char * dir ) {
if ( dir = = NULL ) { return ; }
struct stat st = { 0 } ;
if ( stat ( dir , & st ) = = - 1 ) {
if ( mkdir ( dir , 0700 ) = = - 1 ) {
printf ( " ERROR: could not create directory: %s \n " , dir ) ;
exit ( EXIT_FAILURE ) ;
}
printf ( " created directory: %s \n " , dir ) ;
}
}
int find_max_step ( const char * output_log_dir ) {
// find the DONE file in the log dir with highest step count
if ( output_log_dir = = NULL ) { return - 1 ; }
DIR * dir ;
struct dirent * entry ;
int max_step = - 1 ;
dir = opendir ( output_log_dir ) ;
if ( dir = = NULL ) { return - 1 ; }
while ( ( entry = readdir ( dir ) ) ! = NULL ) {
if ( strncmp ( entry - > d_name , " DONE_ " , 5 ) = = 0 ) {
int step = atoi ( entry - > d_name + 5 ) ;
if ( step > max_step ) {
max_step = step ;
}
}
}
closedir ( dir ) ;
return max_step ;
}
2024-04-29 19:54:18 +00:00
# endif