blob: 835af3b6c11e9cad74bb88ab27e2ede26c8c103f [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef MXNET_STORAGE_STORAGE_MANAGER_HELPERS_H_
#define MXNET_STORAGE_STORAGE_MANAGER_HELPERS_H_
#if MXNET_USE_CUDA
#include <cuda_runtime.h>
#include "../common/cuda/utils.h"
#include "../profiler/storage_profiler.h"
typedef mxnet::common::cuda::DeviceStore CudaDeviceStore;
#endif // MXNET_USE_CUDA
#ifndef _WIN32
#if __APPLE__
#include <mach/vm_statistics.h>
#include <mach/mach_types.h>
#include <mach/mach_init.h>
#include <mach/mach_host.h>
#else
#include <sys/sysinfo.h>
#endif // __APPLE__
#else
#include <Windows.h>
#include <process.h>
#endif // _WIN32
#include <tuple>
#include "../common/utils.h"
namespace mxnet {
namespace storage {
/*!
* \brief Abstract class, which contains context specific methods used by PooledStorageManager.
*/
class ContextHelper {
public:
virtual ~ContextHelper() {}
inline void set_initilal_context(const Context& ctx) {
initilal_context_ = ctx;
}
inline const Context& initilal_context() const {
return initilal_context_;
}
virtual std::tuple<size_t, size_t> getMemoryInfo() const = 0;
virtual int Malloc(void** ppNtr, size_t size) const = 0;
virtual void Free(void* dptr) const = 0;
inline size_t freeMemorySize() const {
return std::get<0>(getMemoryInfo());
}
#if MXNET_USE_CUDA
virtual bool contextGPU() const {
return false;
}
virtual const CudaDeviceStore* SetCurrentDevice(const Context& /*ctx*/) const {
return nullptr;
}
#endif
private:
// context used by this Storage Manager
Context initilal_context_;
};
/*!
* \brief Class, which contains the CPU specific methods used by PooledStorageManager.
*/
class ContextHelperCPU : public ContextHelper {
public:
std::tuple<size_t, size_t> getMemoryInfo() const override {
#if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__)
MEMORYSTATUSEX status;
status.dwLength = sizeof(status);
GlobalMemoryStatusEx(&status);
return std::make_tuple(status.ullAvailPhys, status.ullTotalPhys);
#elif __APPLE__
vm_size_t page_size;
vm_statistics64_data_t vm_stats;
mach_port_t mach_port = mach_host_self();
mach_msg_type_number_t count = sizeof(vm_stats) / sizeof(natural_t);
if (KERN_SUCCESS != host_page_size(mach_port, &page_size) ||
KERN_SUCCESS !=
host_statistics64(mach_port, HOST_VM_INFO, (host_info64_t)&vm_stats, &count)) {
LOG(FATAL) << "Cannot get memory information";
}
const size_t free_memory = (uint64_t)vm_stats.free_count * (uint64_t)page_size;
const size_t used_memory = ((uint64_t)vm_stats.active_count +
(uint64_t)vm_stats.inactive_count + (uint64_t)vm_stats.wire_count) *
(uint64_t)page_size;
return std::make_tuple(free_memory, used_memory + free_memory);
#else // Linux
struct sysinfo info = {};
if (sysinfo(&info) < 0)
LOG(FATAL) << "Error: sysinfo failed";
return std::make_tuple(info.freeram, info.totalram);
#endif
}
int Malloc(void** ppNtr, size_t size) const override {
bool success = mxnet::common::AlignedMemAlloc(ppNtr, size, alignment_);
return success ? 0 : -1;
}
void Free(void* dptr) const override {
mxnet::common::AlignedMemFree(dptr);
}
private:
#if MXNET_USE_ONEDNN == 1 || MXNET_USE_INTGEMM == 1
// DNNL requires special alignment. 64 is used by the DNNL library in
// memory allocation.
static constexpr size_t alignment_ = kDNNLAlign;
#else
static constexpr size_t alignment_ = 16;
#endif
};
#if MXNET_USE_CUDA
/*!
* \brief Class, which contains the GPU specific methods used by PooledStorageManager.
*/
class ContextHelperGPU : public ContextHelper {
public:
std::tuple<size_t, size_t> getMemoryInfo() const override {
size_t free, total;
const auto cuda_status = cudaMemGetInfo(&free, &total);
if (cudaSuccess != cuda_status)
LOG(FATAL) << "Error: cudaMemGetInfo fails " << cudaGetErrorString(cuda_status);
return std::make_tuple(free, total);
}
bool contextGPU() const override {
return true;
}
int Malloc(void** ppPntr, size_t size) const override {
return cudaMalloc(ppPntr, size);
}
void Free(void* dptr) const override {
CUDA_CALL(cudaFree(dptr));
}
const CudaDeviceStore* SetCurrentDevice(const Context& ctx) const override {
return new CudaDeviceStore(ctx.real_dev_id(), true);
}
};
/*!
* \brief Class, which contains the CPU_Pinned specific methods used by PooledStorageManager.
* When MxNet is compiled for MXNET_USE_CUDA=0, this class coincides with ContextHelperCPU
*/
class ContextHelperPinned : public ContextHelperGPU {
public:
int Malloc(void** ppPntr, size_t size) const override {
// make the memory available across all devices
return cudaHostAlloc(ppPntr, size, cudaHostAllocPortable);
}
void Free(void* dptr) const override {
CUDA_CALL(cudaFreeHost(dptr));
}
};
#else
typedef ContextHelperCPU ContextHelperPinned;
#endif
} // namespace storage
} // namespace mxnet
#endif // MXNET_STORAGE_STORAGE_MANAGER_HELPERS_H_