logging_resource_adaptor.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020-2023, NVIDIA CORPORATION.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17 
18 #include <rmm/cuda_stream_view.hpp>
19 #include <rmm/detail/error.hpp>
21 
22 #include <fmt/core.h>
23 #include <spdlog/common.h>
24 #include <spdlog/sinks/basic_file_sink.h>
25 #include <spdlog/sinks/ostream_sink.h>
26 #include <spdlog/spdlog.h>
27 
28 #include <cstddef>
29 #include <memory>
30 #include <sstream>
31 #include <string_view>
32 
33 namespace rmm::mr {
50 template <typename Upstream>
52  public:
74  logging_resource_adaptor(Upstream* upstream,
75  std::string const& filename = get_default_filename(),
76  bool auto_flush = false)
77  : logger_{make_logger(filename)}, upstream_{upstream}
78  {
79  RMM_EXPECTS(nullptr != upstream, "Unexpected null upstream resource pointer.");
80 
81  init_logger(auto_flush);
82  }
83 
98  logging_resource_adaptor(Upstream* upstream, std::ostream& stream, bool auto_flush = false)
99  : logger_{make_logger(stream)}, upstream_{upstream}
100  {
101  RMM_EXPECTS(nullptr != upstream, "Unexpected null upstream resource pointer.");
102 
103  init_logger(auto_flush);
104  }
105 
120  logging_resource_adaptor(Upstream* upstream,
121  spdlog::sinks_init_list sinks,
122  bool auto_flush = false)
123  : logger_{make_logger(sinks)}, upstream_{upstream}
124  {
125  RMM_EXPECTS(nullptr != upstream, "Unexpected null upstream resource pointer.");
126 
127  init_logger(auto_flush);
128  }
129 
130  logging_resource_adaptor() = delete;
131  ~logging_resource_adaptor() override = default;
133  logging_resource_adaptor& operator=(logging_resource_adaptor const&) = delete;
135  default;
137  default;
138 
144  [[nodiscard]] Upstream* get_upstream() const noexcept { return upstream_; }
145 
152  [[nodiscard]] bool supports_streams() const noexcept override
153  {
154  return upstream_->supports_streams();
155  }
156 
162  [[nodiscard]] bool supports_get_mem_info() const noexcept override
163  {
164  return upstream_->supports_get_mem_info();
165  }
166 
170  void flush() { logger_->flush(); }
171 
177  [[nodiscard]] std::string header() const
178  {
179  return std::string{"Thread,Time,Action,Pointer,Size,Stream"};
180  }
181 
189  static std::string get_default_filename()
190  {
191  auto* filename = std::getenv("RMM_LOG_FILE");
192  RMM_EXPECTS(filename != nullptr,
193  "RMM logging requested without an explicit file name, but RMM_LOG_FILE is unset");
194  return std::string{filename};
195  }
196 
197  private:
198  static auto make_logger(std::ostream& stream)
199  {
200  return std::make_shared<spdlog::logger>(
201  "RMM", std::make_shared<spdlog::sinks::ostream_sink_mt>(stream));
202  }
203 
204  static auto make_logger(std::string const& filename)
205  {
206  return std::make_shared<spdlog::logger>(
207  "RMM", std::make_shared<spdlog::sinks::basic_file_sink_mt>(filename, true /*truncate file*/));
208  }
209 
210  static auto make_logger(spdlog::sinks_init_list sinks)
211  {
212  return std::make_shared<spdlog::logger>("RMM", sinks);
213  }
214 
218  void init_logger(bool auto_flush)
219  {
220  if (auto_flush) { logger_->flush_on(spdlog::level::info); }
221  logger_->set_pattern("%v");
222  logger_->info(header());
223  logger_->set_pattern("%t,%H:%M:%S.%f,%v");
224  }
225 
251  void* do_allocate(std::size_t bytes, cuda_stream_view stream) override
252  {
253  try {
254  auto const ptr = upstream_->allocate(bytes, stream);
255  logger_->info("allocate,{},{},{}", ptr, bytes, fmt::ptr(stream.value()));
256  return ptr;
257  } catch (...) {
258  logger_->info("allocate failure,{},{},{}", nullptr, bytes, fmt::ptr(stream.value()));
259  throw;
260  }
261  }
262 
277  void do_deallocate(void* ptr, std::size_t bytes, cuda_stream_view stream) override
278  {
279  logger_->info("free,{},{},{}", ptr, bytes, fmt::ptr(stream.value()));
280  upstream_->deallocate(ptr, bytes, stream);
281  }
282 
290  [[nodiscard]] bool do_is_equal(device_memory_resource const& other) const noexcept override
291  {
292  if (this == &other) { return true; }
293  auto const* cast = dynamic_cast<logging_resource_adaptor<Upstream> const*>(&other);
294  if (cast != nullptr) { return upstream_->is_equal(*cast->get_upstream()); }
295  return upstream_->is_equal(other);
296  }
297 
306  [[nodiscard]] std::pair<std::size_t, std::size_t> do_get_mem_info(
307  cuda_stream_view stream) const override
308  {
309  return upstream_->get_mem_info(stream);
310  }
311 
312  // make_logging_adaptor needs access to private get_default_filename
313  template <typename T>
314  // NOLINTNEXTLINE(readability-redundant-declaration)
315  friend logging_resource_adaptor<T> make_logging_adaptor(T* upstream,
316  std::string const& filename,
317  bool auto_flush);
318 
319  std::shared_ptr<spdlog::logger> logger_;
320 
321  Upstream* upstream_;
323 };
324 
337 template <typename Upstream>
339  Upstream* upstream,
340  std::string const& filename = logging_resource_adaptor<Upstream>::get_default_filename(),
341  bool auto_flush = false)
342 {
343  return logging_resource_adaptor<Upstream>{upstream, filename, auto_flush};
344 }
345 
357 template <typename Upstream>
359  std::ostream& stream,
360  bool auto_flush = false)
361 {
362  return logging_resource_adaptor<Upstream>{upstream, stream, auto_flush};
363 }
364  // end of group
366 } // namespace rmm::mr
Base class for all libcudf device memory allocation.
Definition: device_memory_resource.hpp:89
Resource that uses Upstream to allocate memory and logs information about the requested allocation/de...
Definition: logging_resource_adaptor.hpp:51
std::string header() const
Return the CSV header string.
Definition: logging_resource_adaptor.hpp:177
Upstream * get_upstream() const noexcept
Return pointer to the upstream resource.
Definition: logging_resource_adaptor.hpp:144
void flush()
Flush logger contents.
Definition: logging_resource_adaptor.hpp:170
logging_resource_adaptor(Upstream *upstream, std::string const &filename=get_default_filename(), bool auto_flush=false)
Construct a new logging resource adaptor using upstream to satisfy allocation requests and logging in...
Definition: logging_resource_adaptor.hpp:74
static std::string get_default_filename()
Return the value of the environment variable RMM_LOG_FILE.
Definition: logging_resource_adaptor.hpp:189
logging_resource_adaptor(logging_resource_adaptor &&) noexcept=default
Default move constructor.
logging_resource_adaptor(Upstream *upstream, std::ostream &stream, bool auto_flush=false)
Construct a new logging resource adaptor using upstream to satisfy allocation requests and logging in...
Definition: logging_resource_adaptor.hpp:98
bool supports_get_mem_info() const noexcept override
Query whether the resource supports the get_mem_info API.
Definition: logging_resource_adaptor.hpp:162
logging_resource_adaptor(Upstream *upstream, spdlog::sinks_init_list sinks, bool auto_flush=false)
Construct a new logging resource adaptor using upstream to satisfy allocation requests and logging in...
Definition: logging_resource_adaptor.hpp:120
bool supports_streams() const noexcept override
Checks whether the upstream resource supports streams.
Definition: logging_resource_adaptor.hpp:152
logging_resource_adaptor< Upstream > make_logging_adaptor(Upstream *upstream, std::ostream &stream, bool auto_flush=false)
Convenience factory to return a logging_resource_adaptor around the upstream resource upstream.
Definition: logging_resource_adaptor.hpp:358