LCOV - code coverage report
Current view: top level - nntrainer/tensor - swap_device.cpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 0.0 % 67 0
Test Date: 2025-12-14 20:38:17 Functions: 0.0 % 4 0

            Line data    Source code
       1              : // SPDX-License-Identifier: Apache-2.0
       2              : /**
       3              :  * Copyright (C) 2022 Jiho Chu <jiho.chu@samsung.com>
       4              :  *
       5              :  * @file   swap_device.cpp
       6              :  * @date   01 July 2022
       7              :  * @see    https://github.com/nnstreamer/nntrainer
       8              :  * @author Jiho Chu <jiho.chu@samsung.com>
       9              :  * @bug    No known bugs except for NYI items
      10              :  * @brief  Swap device class implementation
      11              :  *
      12              :  */
      13              : 
      14              : #include <cstring>
      15              : #include <fcntl.h>
      16              : #include <malloc.h>
      17              : #include <profiler.h>
      18              : #include <stdlib.h>
      19              : 
      20              : #include <nntrainer_error.h>
      21              : #include <nntrainer_log.h>
      22              : #include <swap_device.h>
      23              : 
      24              : #if defined(_WIN32)
      25              : #include <Memoryapi.h>
      26              : #include <Sysinfoapi.h>
      27              : #endif
      28              : 
      29              : namespace nntrainer {
      30              : 
      31            0 : void SwapDevice::start(size_t size, ml::train::ExecutionMode _execution_mode) {
      32            0 :   if (fd > 0)
      33              :     return;
      34              : 
      35            0 :   if (_execution_mode == ml::train::ExecutionMode::TRAIN) {
      36            0 :     fd = open(dev_path.c_str(), O_RDWR | O_CREAT | O_TRUNC | O_SYNC, 0666UL);
      37              :   } else {
      38            0 :     fd = open(dev_path.c_str(), O_RDWR | O_CREAT, 0666UL);
      39            0 :     execution_mode = _execution_mode;
      40              :   }
      41            0 :   NNTR_THROW_IF(fd < 0, std::runtime_error)
      42              :     << "SwapDevice: open file: " << dev_path;
      43              : 
      44              :   off_t off;
      45              : 
      46              :   /* make sparse file */
      47            0 :   off = lseek(fd, size - 1, SEEK_SET);
      48            0 :   NNTR_THROW_IF(off < 0, std::runtime_error)
      49              :     << "SwapDevice: seek file: " << dev_path;
      50              : 
      51            0 :   if (_execution_mode == ml::train::ExecutionMode::TRAIN) {
      52              :     ssize_t len;
      53            0 :     len = write(fd, "", 1);
      54            0 :     NNTR_THROW_IF(len != 1, std::runtime_error)
      55              :       << "SwapDevice: write file: " << dev_path;
      56              :   }
      57            0 :   off = lseek(fd, 0, SEEK_SET);
      58            0 :   NNTR_THROW_IF(off < 0, std::runtime_error)
      59              :     << "SwapDevice: seek file: " << dev_path;
      60              : }
      61              : 
      62            0 : void *SwapDevice::getBuffer(off_t offset, size_t size, void *memory_ptr,
      63              :                             unsigned int id, bool alloc_only) {
      64            0 :   NNTR_THROW_IF(fd <= 0, std::runtime_error)
      65              :     << "SwapDevice: Device is not started";
      66              : 
      67              : #ifdef USE_MMAP
      68              : 
      69              : #if defined(_WIN32)
      70              :   SYSTEM_INFO sysInfo;
      71              :   GetSystemInfo(&sysInfo);
      72              :   auto page_size = sysInfo.dwAllocationGranularity;
      73              : #else
      74            0 :   auto page_size = sysconf(_SC_PAGE_SIZE);
      75              : #endif
      76              : 
      77            0 :   if (execution_mode == ml::train::ExecutionMode::INFERENCE) {
      78              :     // FSU Load Weights
      79            0 :     auto len_offset = weight_offset.at(id);
      80            0 :     size_t off = (len_offset.first / page_size) * page_size;
      81            0 :     size_t diff = len_offset.first - off;
      82            0 :     size_t len = len_offset.second + diff;
      83              : 
      84              :     char *ptr = static_cast<char *>(
      85            0 :       mmap(nullptr, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, off));
      86              : 
      87              :     const size_t error_buflen = 100;
      88              :     char error_buf[error_buflen];
      89            0 :     NNTR_THROW_IF(ptr == MAP_FAILED, std::runtime_error)
      90            0 :       << "SwapDevice: mmap: " << SAFE_STRERROR(errno, error_buf, error_buflen);
      91              : 
      92              : #if !defined(__ANDROID__) && !defined(_WIN32)
      93              :     // MADVISE can be used to improve performance.
      94            0 :     mlock(ptr, len);
      95            0 :     madvise(ptr, len, MADV_SEQUENTIAL);
      96              : #endif
      97              : 
      98            0 :     void *buf = static_cast<void *>(ptr + diff);
      99              : 
     100              :     memcpy(memory_ptr, buf, len_offset.second);
     101            0 :     const auto ret = munmap(ptr, len);
     102              : 
     103            0 :     NNTR_THROW_IF(ret == -1, std::runtime_error)
     104              :       << "SwapDevice: munmap: "
     105            0 :       << SAFE_STRERROR(errno, error_buf, error_buflen);
     106              : 
     107              :     return memory_ptr;
     108              :   } else {
     109            0 :     size_t off = (offset / page_size) * page_size;
     110            0 :     size_t diff = offset - off;
     111            0 :     size_t len = size + diff;
     112              :     const size_t error_buflen = 100;
     113              :     char error_buf[error_buflen];
     114              :     char *ptr = static_cast<char *>(
     115            0 :       mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, off));
     116            0 :     NNTR_THROW_IF(ptr == MAP_FAILED, std::runtime_error)
     117            0 :       << "SwapDevice: mmap: " << SAFE_STRERROR(errno, error_buf, error_buflen);
     118            0 :     void *buf = static_cast<void *>(ptr + diff);
     119              : 
     120            0 :     std::lock_guard<std::mutex> lock(mutex);
     121            0 :     mapped[buf] = std::make_tuple(ptr, len, offset, (ssize_t)size);
     122              : 
     123            0 :     return buf;
     124              :   }
     125              : #else
     126              :   off_t off;
     127              :   ssize_t len;
     128              :   void *ptr;
     129              : 
     130              :   ptr = calloc(1, size);
     131              :   NNTR_THROW_IF(ptr == NULL, std::runtime_error)
     132              :     << "SwapDevice: memory alloc failed";
     133              : 
     134              :   if (!alloc_only) {
     135              :     off = lseek(fd, offset, SEEK_SET);
     136              :     NNTR_THROW_IF(off < 0, std::runtime_error)
     137              :       << "SwapDevice: seek file: " << dev_path;
     138              : 
     139              :     len = read(fd, ptr, size);
     140              :     NNTR_THROW_IF(len != (size_t)size, std::runtime_error)
     141              :       << "SwapDevice: read file: " << dev_path;
     142              :   }
     143              : 
     144              :   {
     145              :     std::lock_guard<std::mutex> lock(mutex);
     146              :     allocated[ptr] = std::make_pair(offset, (ssize_t)size);
     147              :   }
     148              : 
     149              :   return ptr;
     150              : #endif
     151              : }
     152              : 
     153            0 : void SwapDevice::putBuffer(void *ptr, bool dealloc_only) {
     154            0 :   NNTR_THROW_IF(fd <= 0, std::runtime_error)
     155              :     << "SwapDevice: Device is not started";
     156              : #ifdef USE_MMAP
     157              :   decltype(mapped)::mapped_type info;
     158              :   {
     159            0 :     std::lock_guard<std::mutex> lock(mutex);
     160              :     auto it = mapped.find(ptr);
     161            0 :     NNTR_THROW_IF(it == mapped.end(), std::runtime_error)
     162              :       << "Couldn't find buffer";
     163              :     info = it->second;
     164              :   }
     165              : 
     166              :   off_t off;
     167              :   ssize_t len;
     168            0 :   if (!dealloc_only) {
     169            0 :     off = lseek(fd, std::get<2>(info), SEEK_SET);
     170            0 :     NNTR_THROW_IF(off < 0, std::runtime_error)
     171              :       << "SwapDevice: seek file: " << dev_path;
     172              : 
     173              :     ssize_t size = std::get<3>(info);
     174            0 :     len = write(fd, ptr, size);
     175            0 :     NNTR_THROW_IF(len != size, std::runtime_error)
     176            0 :       << "SwapDevice: write file: " << len << "::" << std::to_string(size)
     177              :       << dev_path;
     178              :   }
     179              : 
     180            0 :   const auto ret = munmap(std::get<void *>(info), std::get<size_t>(info));
     181              :   const size_t error_buflen = 100;
     182              :   char error_buf[error_buflen];
     183            0 :   NNTR_THROW_IF(ret == -1, std::runtime_error)
     184            0 :     << "SwapDevice: munmap: " << SAFE_STRERROR(errno, error_buf, error_buflen);
     185              : 
     186              :   {
     187              :     std::lock_guard<std::mutex> lock(mutex);
     188              :     mapped.erase(ptr);
     189              :   }
     190              : 
     191              : #if !defined(__ANDROID__) && !defined(_WIN32)
     192            0 :   madvise(std::get<void *>(info), std::get<size_t>(info), MADV_FREE);
     193              : #endif
     194              : 
     195              : #else
     196              :   decltype(allocated)::mapped_type info;
     197              :   {
     198              :     std::lock_guard<std::mutex> lock(mutex);
     199              :     auto it = allocated.find(ptr);
     200              :     NNTR_THROW_IF(it == allocated.end(), std::invalid_argument)
     201              :       << "SwapDevice: Couldn't find buffer";
     202              :     info = it->second;
     203              :   }
     204              :   off_t off;
     205              :   ssize_t len;
     206              : 
     207              :   auto [offset, size] = info;
     208              : 
     209              :   if (!dealloc_only) {
     210              :     off = lseek(fd, offset, SEEK_SET);
     211              :     NNTR_THROW_IF(off < 0, std::runtime_error)
     212              :       << "SwapDevice: seek file: " << dev_path;
     213              : 
     214              :     len = write(fd, ptr, size);
     215              :     NNTR_THROW_IF(len != size, std::runtime_error)
     216              :       << "SwapDevice: write file: " << dev_path;
     217              :   }
     218              : 
     219              :   free(ptr);
     220              :   {
     221              :     std::lock_guard<std::mutex> lock(mutex);
     222              :     allocated.erase(ptr);
     223              :   }
     224              : 
     225              : #if !defined(__ANDROID__) && !defined(_WIN32)
     226              :   malloc_trim(0);
     227              : #endif
     228              : 
     229              : #endif
     230            0 : }
     231              : 
     232              : /**
     233              :  * @brief Close device
     234              :  *
     235              :  */
     236            0 : void SwapDevice::finish() {
     237            0 :   if (fd < 0)
     238              :     return;
     239              : 
     240              : #ifdef USE_MMAP
     241            0 :   if (execution_mode == ml::train::ExecutionMode::TRAIN) {
     242            0 :     for (auto &[ptr, info] : mapped) {
     243            0 :       if (ptr)
     244            0 :         free(ptr);
     245              :     }
     246              :   }
     247              :   mapped.clear();
     248              : #else
     249              :   for (auto &alloc : allocated)
     250              :     free(alloc.first);
     251              :   allocated.clear();
     252              : #endif
     253              : 
     254            0 :   close(fd);
     255            0 :   fd = -1;
     256            0 :   if (execution_mode == ml::train::ExecutionMode::TRAIN) {
     257            0 :     int status = std::remove(dev_path.c_str());
     258            0 :     NNTR_THROW_IF(status, std::runtime_error)
     259              :       << "SwapDevice: Couldn't remove " << dev_path.c_str();
     260              :   }
     261              : }
     262              : 
     263              : } // namespace nntrainer
        

Generated by: LCOV version 2.0-1