Skip to content

Commit 4c60b92

Browse files
Copilotnjzjz
andcommitted
Fix cross-platform compatibility for directory creation and path handling
Co-authored-by: njzjz <9496702+njzjz@users.noreply.github.com>
1 parent 101a901 commit 4c60b92

5 files changed

Lines changed: 75 additions & 10 deletions

File tree

File renamed without changes.

source/api_cc/include/common.h

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,11 +173,26 @@ void get_env_nthreads(int& num_intra_nthreads, int& num_inter_nthreads);
173173
void get_env_pytorch_profiler(bool& enable_profiler, std::string& output_dir);
174174

175175
/**
176-
* @brief Get MPI rank if MPI is available and initialized, otherwise return 0.
177-
* @return The MPI rank or 0 if MPI is not available/initialized.
176+
* @brief Get MPI rank if MPI is available and initialized, otherwise return -1.
177+
* @return The MPI rank or -1 if MPI is not available/initialized.
178178
**/
179179
int get_mpi_rank();
180180

181+
/**
182+
* @brief Create directories recursively in a cross-platform way.
183+
* @param path The path to create.
184+
* @return true if successful or directory already exists, false otherwise.
185+
**/
186+
bool create_directories(const std::string& path);
187+
188+
/**
189+
* @brief Join two path components using platform-appropriate separator.
190+
* @param path1 The first path component.
191+
* @param path2 The second path component.
192+
* @return The joined path.
193+
**/
194+
std::string join_path(const std::string& path1, const std::string& path2);
195+
181196
/**
182197
* @brief Dynamically load OP library. This should be called before loading
183198
* graphs.

source/api_cc/src/DeepPotPT.cc

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,9 @@ void DeepPotPT::init(const std::string& model,
115115
if (profiler_enabled) {
116116
#ifdef BUILD_PYTORCH
117117
// Create output directory if it doesn't exist
118-
std::string mkdir_cmd = "mkdir -p " + profiler_output_dir;
119-
std::system(mkdir_cmd.c_str());
118+
if (!create_directories(profiler_output_dir)) {
119+
std::cerr << "Warning: Failed to create profiler output directory: " << profiler_output_dir << std::endl;
120+
}
120121

121122
std::cout << "PyTorch profiler enabled. Output directory: " << profiler_output_dir << std::endl;
122123
// Start profiling using new API
@@ -147,10 +148,10 @@ DeepPotPT::~DeepPotPT() {
147148
std::string output_file;
148149
if (rank >= 0) {
149150
// MPI is available and initialized, include rank in filename
150-
output_file = profiler_output_dir + "/pytorch_profiler_trace_rank" + std::to_string(rank) + ".json";
151+
output_file = join_path(profiler_output_dir, "pytorch_profiler_trace_rank" + std::to_string(rank) + ".json");
151152
} else {
152153
// MPI not available or not initialized, use original filename
153-
output_file = profiler_output_dir + "/pytorch_profiler_trace.json";
154+
output_file = join_path(profiler_output_dir, "pytorch_profiler_trace.json");
154155
}
155156
profiler_result = torch::profiler::disableProfiler();
156157
if (profiler_result) {

source/api_cc/src/DeepSpinPT.cc

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,9 @@ void DeepSpinPT::init(const std::string& model,
115115
if (profiler_enabled) {
116116
#ifdef BUILD_PYTORCH
117117
// Create output directory if it doesn't exist
118-
std::string mkdir_cmd = "mkdir -p " + profiler_output_dir;
119-
std::system(mkdir_cmd.c_str());
118+
if (!create_directories(profiler_output_dir)) {
119+
std::cerr << "Warning: Failed to create profiler output directory: " << profiler_output_dir << std::endl;
120+
}
120121

121122
std::cout << "PyTorch profiler enabled. Output directory: " << profiler_output_dir << std::endl;
122123
// Start profiling using new API
@@ -147,10 +148,10 @@ DeepSpinPT::~DeepSpinPT() {
147148
std::string output_file;
148149
if (rank >= 0) {
149150
// MPI is available and initialized, include rank in filename
150-
output_file = profiler_output_dir + "/pytorch_profiler_trace_rank" + std::to_string(rank) + ".json";
151+
output_file = join_path(profiler_output_dir, "pytorch_profiler_trace_rank" + std::to_string(rank) + ".json");
151152
} else {
152153
// MPI not available or not initialized, use original filename
153-
output_file = profiler_output_dir + "/pytorch_profiler_trace.json";
154+
output_file = join_path(profiler_output_dir, "pytorch_profiler_trace.json");
154155
}
155156
profiler_result = torch::profiler::disableProfiler();
156157
if (profiler_result) {

source/api_cc/src/common.cc

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
#include <fstream>
88
#include <sstream>
99
#include <string>
10+
#include <iostream>
11+
#include <sys/stat.h>
12+
#include <errno.h>
1013

1114
// Try to include MPI if available - this will be a no-op if MPI is not available
1215
#ifdef __has_include
@@ -27,6 +30,7 @@
2730
#define PSAPI_VERSION 2
2831
#include <io.h>
2932
#include <windows.h>
33+
#include <direct.h> // for _mkdir
3034
#define O_RDONLY _O_RDONLY
3135
#else
3236
// not windows
@@ -419,6 +423,50 @@ int deepmd::get_mpi_rank() {
419423
return rank;
420424
}
421425

426+
bool deepmd::create_directories(const std::string& path) {
427+
if (path.empty()) {
428+
return false;
429+
}
430+
431+
// Check if directory already exists
432+
struct stat st;
433+
if (stat(path.c_str(), &st) == 0) {
434+
return S_ISDIR(st.st_mode);
435+
}
436+
437+
// Find the parent directory
438+
size_t pos = path.find_last_of("/\\");
439+
if (pos != std::string::npos && pos > 0) {
440+
std::string parent = path.substr(0, pos);
441+
if (!create_directories(parent)) {
442+
return false;
443+
}
444+
}
445+
446+
// Create this directory
447+
#if defined(_WIN32)
448+
return _mkdir(path.c_str()) == 0 || errno == EEXIST;
449+
#else
450+
return mkdir(path.c_str(), 0755) == 0 || errno == EEXIST;
451+
#endif
452+
}
453+
454+
std::string deepmd::join_path(const std::string& path1, const std::string& path2) {
455+
if (path1.empty()) return path2;
456+
if (path2.empty()) return path1;
457+
458+
char sep = '/';
459+
#if defined(_WIN32)
460+
sep = '\\';
461+
#endif
462+
463+
if (path1.back() == '/' || path1.back() == '\\') {
464+
return path1 + path2;
465+
} else {
466+
return path1 + sep + path2;
467+
}
468+
}
469+
422470
static inline void _load_library_path(std::string dso_path) {
423471
#if defined(_WIN32)
424472
void* dso_handle = LoadLibrary(dso_path.c_str());

0 commit comments

Comments
 (0)