Arcane  v3.15.0.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
arcane/src/arcane/utils/PlatformUtils.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2024 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* PlatformUtils.cc (C) 2000-2024 */
9/* */
10/* Fonctions utilitaires dépendant de la plateforme. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/PlatformUtils.h"
15#include "arcane/utils/String.h"
16#include "arcane/utils/StdHeader.h"
17#include "arcane/utils/StackTrace.h"
18#include "arcane/utils/IStackTraceService.h"
19#include "arcane/utils/IOnlineDebuggerService.h"
20#include "arcane/utils/Iostream.h"
21#include "arcane/utils/StringBuilder.h"
22#include "arcane/utils/NotSupportedException.h"
23#include "arcane/utils/Array.h"
24#include "arcane/utils/StringList.h"
26#include "arcane/utils/internal/MemoryUtilsInternal.h"
27
28#include <chrono>
29
30#ifndef ARCANE_OS_WIN32
31#define ARCANE_OS_UNIX
32#endif
33
34#ifdef ARCANE_OS_WIN32
35#include <sys/types.h>
36#include <sys/timeb.h>
37#include <sys/stat.h>
38#include <direct.h>
39#include <process.h>
40#include <windows.h>
41#include <shlobj.h>
42#endif
43
44#ifdef ARCANE_OS_UNIX
45#include <unistd.h>
46#include <sys/resource.h>
47#include <time.h>
48#include <sys/types.h>
49#include <sys/stat.h>
50#include <sys/time.h>
51#include <fcntl.h>
52#endif
53
54#include <malloc.h>
55
56#if !defined(ARCANE_OS_CYGWIN) && !defined(ARCANE_OS_WIN32)
57#if defined(__i386__)
58#define ARCANE_HAS_I386_FPU_CONTROL_H
59#include <fpu_control.h>
60#endif
61#endif
62
63#ifndef ARCANE_OS_WIN32
64#include <pwd.h>
65#include <sys/types.h>
66#include <unistd.h>
67#endif
68
69// Support pour gérer les exceptions flottantes:
70// - sous Linux avec la GlibC, cela se fait via les méthodes
71// feenableexcept(), fedisableexcept() et fegetexcept()
72// - sous Win32, cela se fait via la méthode _controlfp() mais pour
73// l'instant ce n'est pas utilisé dans Arcane.
74#if defined(ARCANE_OS_LINUX) && defined(__USE_GNU)
75# include <fenv.h>
76# define ARCANE_GLIBC_FENV
77#endif
78
79/*---------------------------------------------------------------------------*/
80/*---------------------------------------------------------------------------*/
81
82namespace Arcane
83{
84
85/*---------------------------------------------------------------------------*/
86/*---------------------------------------------------------------------------*/
87
88namespace platform
89{
90 IOnlineDebuggerService* global_online_debugger_service = nullptr;
91 ISymbolizerService* global_symbolizer_service = nullptr;
92 IProfilingService* global_profiling_service = nullptr;
93 IProcessorAffinityService* global_processor_affinity_service = nullptr;
94 IDynamicLibraryLoader* global_dynamic_library_loader = nullptr;
95 IPerformanceCounterService* global_performance_counter_service = nullptr;
96 bool global_has_color_console = false;
97}
98
99/*---------------------------------------------------------------------------*/
100/*---------------------------------------------------------------------------*/
101
102extern "C++" ARCANE_UTILS_EXPORT ISymbolizerService* platform::
104{
105 return global_symbolizer_service;
106}
107
108/*---------------------------------------------------------------------------*/
109/*---------------------------------------------------------------------------*/
110
111extern "C++" ARCANE_UTILS_EXPORT ISymbolizerService* platform::
113{
114 ISymbolizerService* old_service = global_symbolizer_service;
115 global_symbolizer_service = service;
116 return old_service;
117}
118
119/*---------------------------------------------------------------------------*/
120/*---------------------------------------------------------------------------*/
121
122extern "C++" ARCANE_UTILS_EXPORT IOnlineDebuggerService* platform::
124{
125 return global_online_debugger_service;
126}
127
128/*---------------------------------------------------------------------------*/
129/*---------------------------------------------------------------------------*/
130
131extern "C++" ARCANE_UTILS_EXPORT IOnlineDebuggerService* platform::
133{
134 IOnlineDebuggerService* old_service = global_online_debugger_service;
135 global_online_debugger_service = service;
136 return old_service;
137}
138
139/*---------------------------------------------------------------------------*/
140/*---------------------------------------------------------------------------*/
141
142extern "C++" ARCANE_UTILS_EXPORT IProfilingService* platform::
144{
145 return global_profiling_service;
146}
147
148/*---------------------------------------------------------------------------*/
149/*---------------------------------------------------------------------------*/
150
151extern "C++" ARCANE_UTILS_EXPORT IProfilingService* platform::
153{
154 IProfilingService* old_service = global_profiling_service;
155 global_profiling_service = service;
156 return old_service;
157}
158
159/*---------------------------------------------------------------------------*/
160/*---------------------------------------------------------------------------*/
161
162extern "C++" ARCANE_UTILS_EXPORT IDynamicLibraryLoader* platform::
164{
165 return global_dynamic_library_loader;
166}
167
168/*---------------------------------------------------------------------------*/
169/*---------------------------------------------------------------------------*/
170
171extern "C++" ARCANE_UTILS_EXPORT IDynamicLibraryLoader* platform::
173{
174 IDynamicLibraryLoader* old_service = global_dynamic_library_loader;
175 global_dynamic_library_loader = idll;
176 return old_service;
177}
178
179/*---------------------------------------------------------------------------*/
180/*---------------------------------------------------------------------------*/
181
182extern "C++" ARCANE_UTILS_EXPORT IProcessorAffinityService* platform::
184{
185 return global_processor_affinity_service;
186}
187
188/*---------------------------------------------------------------------------*/
189/*---------------------------------------------------------------------------*/
190
191extern "C++" ARCANE_UTILS_EXPORT IProcessorAffinityService* platform::
193{
194 IProcessorAffinityService* old_service = global_processor_affinity_service;
195 global_processor_affinity_service = service;
196 return old_service;
197}
198
199/*---------------------------------------------------------------------------*/
200/*---------------------------------------------------------------------------*/
201
202extern "C++" ARCANE_UTILS_EXPORT IPerformanceCounterService* platform::
204{
205 return global_performance_counter_service;
206}
207
208/*---------------------------------------------------------------------------*/
209/*---------------------------------------------------------------------------*/
210
211extern "C++" ARCANE_UTILS_EXPORT IPerformanceCounterService* platform::
213{
214 auto* old_service = global_performance_counter_service;
215 global_performance_counter_service = service;
216 return old_service;
217}
218
219/*---------------------------------------------------------------------------*/
220/*---------------------------------------------------------------------------*/
221
222extern "C++" ARCANE_UTILS_EXPORT IMemoryAllocator* platform::
223getAcceleratorHostMemoryAllocator()
224{
225 return MemoryUtils::getAcceleratorHostMemoryAllocator();
226}
227
228/*---------------------------------------------------------------------------*/
229/*---------------------------------------------------------------------------*/
230
231extern "C++" ARCANE_UTILS_EXPORT IMemoryAllocator* platform::
232setAcceleratorHostMemoryAllocator(IMemoryAllocator* a)
233{
235}
236
237/*---------------------------------------------------------------------------*/
238/*---------------------------------------------------------------------------*/
239
245
246/*---------------------------------------------------------------------------*/
247/*---------------------------------------------------------------------------*/
248
249extern "C++" ARCANE_UTILS_EXPORT IMemoryRessourceMng* platform::
250setDataMemoryRessourceMng(IMemoryRessourceMng* mng)
251{
253}
254
255/*---------------------------------------------------------------------------*/
256/*---------------------------------------------------------------------------*/
257
258IMemoryRessourceMng* platform::
259getDataMemoryRessourceMng()
260{
262}
263
264/*---------------------------------------------------------------------------*/
265/*---------------------------------------------------------------------------*/
266
267extern "C++" ARCANE_UTILS_EXPORT IThreadImplementation* platform::
269{
270 return Arccore::Concurrency::getThreadImplementation();
271}
272
273/*---------------------------------------------------------------------------*/
274/*---------------------------------------------------------------------------*/
275
276extern "C++" ARCANE_UTILS_EXPORT IThreadImplementation* platform::
278{
279 return Arccore::Concurrency::setThreadImplementation(service);
280}
281
282/*---------------------------------------------------------------------------*/
283/*---------------------------------------------------------------------------*/
284
285extern "C++" ARCANE_UTILS_EXPORT void platform::
287{
288#ifdef ARCANE_OS_UNIX
289 struct itimerval time_val;
290 struct itimerval otime_val;
291 time_val.it_value.tv_sec = nb_second;
292 time_val.it_value.tv_usec = 0;
293 time_val.it_interval.tv_sec = 0;
294 time_val.it_interval.tv_usec = 0;
295 // Utilise le temps virtuel et pas le temps réel.
296 // Cela permet de suspendre temporairement un job (par exemple
297 // pour régler des problèmes systèmes) sans déclencher l'alarme.
299 if (r!=0)
300 cout << "** ERROR in setitimer r=" << r << '\n';
301#endif
302}
303
304/*---------------------------------------------------------------------------*/
305/*---------------------------------------------------------------------------*/
306
307extern "C++" ARCANE_UTILS_EXPORT void platform::
309{
311}
312
313/*---------------------------------------------------------------------------*/
314/*---------------------------------------------------------------------------*/
315
316extern "C++" ARCANE_UTILS_EXPORT void platform::
318{
320}
321
322/*---------------------------------------------------------------------------*/
323/*---------------------------------------------------------------------------*/
324
325namespace
326{
327template<typename ByteType> bool
329{
330 using namespace std;
331 long unsigned int file_length = platform::getFileLength(filename);
332 if (file_length == 0) {
333 //cerr << "** FAIL LENGTH\n";
334 return true;
335 }
336 ifstream ifile;
337 ios::openmode mode = ios::in;
338 if (is_binary)
339 mode |= ios::binary;
340 ifile.open(filename.toStdStringView().data());
341 if (ifile.fail()) {
342 //cerr << "** FAIL OPEN\n";
343 return true;
344 }
345 out_bytes.resize(file_length);
346 ifile.read((char*)(out_bytes.data()), file_length);
347 if (ifile.bad()) {
348 // cerr << "** BAD READ\n";
349 return true;
350 }
351 // Il est possible que le nombre d'octets lus soit inférieur
352 // à la longueur du fichier, notamment sous Windows avec les fichiers
353 // texte et la conversion des retour-chariots. Il faut donc redimensionner
354 // \a bytes à la bonne longueur.
355 size_t nb_read = ifile.gcount();
356 out_bytes.resize(nb_read);
357 //cerr << "** READ " << file_length << " bytes " << (const char*)(bytes.begin()) << "\n";
358 return false;
359}
360}
361
362/*---------------------------------------------------------------------------*/
363/*---------------------------------------------------------------------------*/
364
367{
368 return _readAllFile(filename,is_binary,out_bytes);
369}
370
371/*---------------------------------------------------------------------------*/
372/*---------------------------------------------------------------------------*/
373
376{
377 return _readAllFile(filename,is_binary,out_bytes);
378}
379
380/*---------------------------------------------------------------------------*/
381/*---------------------------------------------------------------------------*/
382
383static bool global_has_dotnet_runtime = false;
384extern "C++" bool platform::
386{
387 return global_has_dotnet_runtime;
388}
389
390extern "C++" void platform::
392{
393 global_has_dotnet_runtime = v;
394}
395
396/*---------------------------------------------------------------------------*/
397/*---------------------------------------------------------------------------*/
398
399extern "C++" String platform::
401{
403#if defined(ARCANE_OS_LINUX)
404 char* buf = ::realpath("/proc/self/exe",nullptr);
405 if (buf){
406 full_path = StringView(buf);
407 ::free(buf);
408 }
409#elif defined(ARCANE_OS_WIN32)
410 char buf[2048];
411 int r = GetModuleFileNameA(NULL,buf,2000);
412 if (r>0){
413 full_path = StringView(buf);
414 }
415#else
416#error "platform::getExeFullPath() not implemented for this platform"
417#endif
418 return full_path;
419}
420
421/*---------------------------------------------------------------------------*/
422/*---------------------------------------------------------------------------*/
423
424extern "C++" String platform::
426{
428 if (dll_name.null())
429 return full_path;
430#if defined(ARCANE_OS_LINUX)
431 {
432 std::ifstream ifile("/proc/self/maps");
433 String v;
434 String true_name = "lib" + dll_name + ".so";
435 while (ifile.good()){
436 ifile >> v;
437 Span<const Byte> vb = v.bytes();
438 if (vb.size()>0 && vb[0]=='/'){
439 if (v.endsWith(true_name)){
440 full_path = v;
441 //std::cout << "V='" << v << "'\n";
442 break;
443 }
444 }
445 }
446 }
447#elif defined(ARCANE_OS_WIN32)
449 if (!hModule)
450 return full_path;
454#else
455 throw NotSupportedException(A_FUNCINFO);
456//#error "platform::getSymbolFullPath() not implemented for this platform"
457#endif
458 return full_path;
459}
460
461/*---------------------------------------------------------------------------*/
462/*---------------------------------------------------------------------------*/
463
464extern "C++" void platform::
466{
467 arg_list.clear();
468#if defined(ARCANE_OS_LINUX)
469
470 const int BUFSIZE = 1024;
471 char buffer[BUFSIZE + 1];
472
473 UniqueArray<char> bytes;
474 bytes.reserve(1024);
475
476 {
477 const char* filename = "/proc/self/cmdline";
478 int fd = open(filename, O_RDONLY);
479 if (fd<0)
480 return;
481 ssize_t nb_read = 0;
482 // TODO: traiter les interruptions
483 while ((nb_read = read(fd, buffer, BUFSIZE)) > 0) {
484 buffer[BUFSIZE] = '\0';
485 bytes.addRange(Span<const char>(buffer, nb_read));
486 }
487 close(fd);
488 }
489
490 int size = bytes.size();
491 const char* ptr = bytes.data();
492 const char* end = ptr + size;
493 while (ptr < end) {
494 arg_list.add(StringView(ptr));
495 while (*ptr++ && ptr < end)
496 ;
497 }
498#endif
499}
500
501/*---------------------------------------------------------------------------*/
502/*---------------------------------------------------------------------------*/
503// TODO: mettre ensuite dans 'Arccore'
504
505extern "C++" ARCANE_UTILS_EXPORT Int64 platform::
507{
508 auto x = std::chrono::high_resolution_clock::now();
509 // Converti la valeur en nanosecondes.
510 auto y = std::chrono::time_point_cast<std::chrono::nanoseconds>(x);
511 // Retourne le temps en nano-secondes.
512 return static_cast<Int64>(y.time_since_epoch().count());
513}
514
515/*---------------------------------------------------------------------------*/
516/*---------------------------------------------------------------------------*/
517
518extern "C++" ARCANE_UTILS_EXPORT Int64 platform::
520{
521#if defined(ARCCORE_OS_WIN32)
524 return si.dwPageSize;
525#elif defined(ARCANE_OS_LINUX)
526 return ::sysconf(_SC_PAGESIZE);
527#else
528#warning "getPageSize() not implemented for your platform. Default is 4096"
529 Int64 page_size = 4096;
530 return page_size;
531#endif
532}
533
534/*---------------------------------------------------------------------------*/
535/*---------------------------------------------------------------------------*/
536
537namespace
538{
539 String _getDebuggerStack(const char* command)
540 {
541 char filename[4096];
542 long pid = (long)getpid();
543 sprintf(filename, "errlog.%ld", pid);
544 int ret_value = system(command);
545 if (ret_value != 0) {
546 UniqueArray<Byte> bytes;
547 if (!platform::readAllFile(filename, false, bytes))
548 return String(bytes);
549 }
550 return {};
551 }
552} // namespace
553
554extern "C++" ARCANE_UTILS_EXPORT String platform::
556{
557 String result;
558#if defined(ARCANE_OS_LINUX)
559 const size_t cmd_size = 4096;
560 char cmd[cmd_size + 1];
561 //sprintf (cmd, "gdb --ex 'attach %ld' --ex 'info threads' --ex 'thread apply all bt'", (long)getpid ());
562 //sprintf (cmd, "gdb --ex 'attach %ld' --ex 'info threads' --ex 'thread apply all bt' --batch", (long)getpid ());
563 long pid = (long)getpid();
564 snprintf(cmd, cmd_size, "gdb --ex 'set debuginfod enabled off' --ex 'attach %ld' --ex 'info threads' --ex 'thread apply all bt full' --batch", pid);
565 result = _getDebuggerStack(cmd);
566#endif
567 return result;
568}
569
570/*---------------------------------------------------------------------------*/
571/*---------------------------------------------------------------------------*/
572
573extern "C++" ARCANE_UTILS_EXPORT String platform::
575{
576 String result;
577#if defined(ARCANE_OS_LINUX)
578 const size_t cmd_size = 4096;
579 char cmd[cmd_size + 1];
580 long pid = (long)getpid();
581 // Les commandes 'clrthreads', 'clrstack' et 'dumpstack' nécessitent
582 // d'avoir installé 'dotnet-sos'.
583 snprintf(cmd, cmd_size, "lldb -p %ld -o 'bt' -o 'bt all' -o 'clrthreads' -o 'clrstack' -o 'dumpstack' --batch", pid);
584 result = _getDebuggerStack(cmd);
585#endif
586 return result;
587}
588
589/*---------------------------------------------------------------------------*/
590/*---------------------------------------------------------------------------*/
591
592namespace
593{
595}
596
597extern "C" ARCANE_UTILS_EXPORT void
598_ArcaneSetCallGarbageCollectorDelegate(void(*f)())
599{
600 global_garbage_collector_delegate = f;
601}
602
603extern "C++" void platform::
605{
607 (*global_garbage_collector_delegate)();
608}
609
610/*---------------------------------------------------------------------------*/
611/*---------------------------------------------------------------------------*/
612
613} // End namespace Arcane
614
615/*---------------------------------------------------------------------------*/
616/*---------------------------------------------------------------------------*/
Fonctions de gestion mémoire et des allocateurs.
Tableau d'items de types quelconques.
Interface d'une chargeur dynamique de bibliothèque.
Gestion des ressources mémoire pour les CPU et accélérateurs.
Interface d'un service de debugger hybrid.
Interface d'un service d'accès aux compteurs de performance.
Interface d'un service de de trace des appels de fonctions.
Interface d'un service de profiling.
Interface d'un service de récupération des symboles du code source.
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Definition Lima.cc:149
Interface d'un service implémentant le support des threads.
Exception lorsqu'une opération n'est pas supportée.
Vue sur une chaîne de caractères UTF-8.
Definition StringView.h:47
std::string_view toStdStringView() const ARCCORE_NOEXCEPT
Retourne une vue de la STL de la vue actuelle.
Definition StringView.h:112
Chaîne de caractères unicode.
IMemoryRessourceMng * setDataMemoryResourceMng(IMemoryRessourceMng *mng)
Positionne le gestionnaire de ressource mémoire pour les données.
IMemoryRessourceMng * getDataMemoryResourceMng()
Gestionnaire de ressource mémoire pour les données.
IMemoryAllocator * setAcceleratorHostMemoryAllocator(IMemoryAllocator *a)
Positionne l'allocateur spécifique pour les accélérateurs.
IMemoryAllocator * getDefaultDataAllocator()
Allocateur par défaut pour les données.
IPerformanceCounterService * setPerformanceCounterService(IPerformanceCounterService *service)
Positionne le service utilisé pour gérer les compteurs interne du processeur.
void callDotNETGarbageCollector()
Appelle le Garbage Collector de '.Net' s'il est disponible.
String getLLDBStack()
Récupère la pile d'appel via lldb.
String getLoadedSharedLibraryFullPath(const String &dll_name)
Retourne le chemin complet d'une bibliothèque dynamique chargée.
ISymbolizerService * setSymbolizerService(ISymbolizerService *service)
Positionne le service pour obtenir des informations sur les symboles du code source.
IDynamicLibraryLoader * getDynamicLibraryLoader()
Service utilisé pour charger dynamiquement des bibliothèques.
void fillCommandLineArguments(StringList &arg_list)
Remplit arg_list avec les arguments de la ligne de commande.
void platformInitialize()
Initialisations spécifiques à une platforme.
IOnlineDebuggerService * setOnlineDebuggerService(IOnlineDebuggerService *service)
Positionne le service a utiliser pour l'architecture en ligne de debug.
ISymbolizerService * getSymbolizerService()
Service utilisé pour obtenir des informations sur les symboles du code source.
IProfilingService * getProfilingService()
Service utilisé pour obtenir pour obtenir des informations de profiling.
void resetAlarmTimer(Integer nb_second)
Remet à timer d'alarme à nb_second.
void platformTerminate()
Routines de fin de programme spécifiques à une platforme.
IProfilingService * setProfilingService(IProfilingService *service)
Positionne le service utilisé pour obtenir des informations de profiling.
IMemoryAllocator * getDefaultDataAllocator()
Allocateur par défaut pour les données.
Int64 getPageSize()
Taille des pages du système hôte en octets.
String getExeFullPath()
Retourne le nom complet avec le chemin de l'exécutable.
Int64 getRealTimeNS()
Temps horloge en nano-secondes.
bool readAllFile(StringView filename, bool is_binary, ByteArray &out_bytes)
Lit le contenu d'un fichier et le conserve dans out_bytes.
IProcessorAffinityService * setProcessorAffinityService(IProcessorAffinityService *service)
Positionne le service utilisé pour la gestion de l'affinité des processeurs.
void setHasDotNETRuntime(bool v)
Positionne si le code s'exécute avec le runtime .NET.
IProcessorAffinityService * getProcessorAffinityService()
Service utilisé pour la gestion de l'affinité des processeurs.
IThreadImplementation * getThreadImplementationService()
Service utilisé pour gérer les threads.
IDynamicLibraryLoader * setDynamicLibraryLoader(IDynamicLibraryLoader *idll)
Positionne le service utilisé pour charger dynamiquement des bibliothèques.
IPerformanceCounterService * getPerformanceCounterService()
Service utilisé pour obtenir pour obtenir les compteurs interne du processeur.
bool hasDotNETRuntime()
Vrai si le code s'exécute avec le runtime .NET.
String getGDBStack()
Récupère la pile d'appel via gdb.
IThreadImplementation * setThreadImplementationService(IThreadImplementation *service)
Positionne le service utilisé pour gérer les threads.
IOnlineDebuggerService * getOnlineDebuggerService()
Service utilisé pour obtenir la mise en place d'une architecture en ligne de debug.
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
ARCCORE_BASE_EXPORT void platformInitialize()
Initialisations spécifiques à une platforme.
ARCCORE_BASE_EXPORT void platformTerminate()
Routines de fin de programme spécifiques à une platforme.