Skip to content

Commit a7eafae

Browse files
Merge pull request #718 from vlad-perevezentsev/use_glog
Implementation of GLog
2 parents 66c885c + 84e7dc5 commit a7eafae

File tree

10 files changed

+298
-14
lines changed

10 files changed

+298
-14
lines changed

.flake8

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ exclude =
1313
.git
1414

1515
per-file-ignores =
16+
dpctl/_diagnostics.pyx: E999
1617
dpctl/_sycl_context.pyx: E999, E225, E227
1718
dpctl/_sycl_device.pyx: E999, E225
1819
dpctl/_sycl_device_factory.pyx: E999, E225

CONTRIBUTING.md

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,13 +161,12 @@ these steps:
161161
3. Build dpctl with code coverage support.
162162

163163
```bash
164-
python setup.py develop --coverage=True
165-
pytest -q -ra --disable-warnings --cov dpctl --cov-report term-missing --pyargs dpctl -vv
164+
python scripts/gen_coverage.py --oneapi
166165
coverage html
167166
```
168167

169168
Note that code coverage builds the C sources with debug symbols. For this
170-
reason, the coverage flag is only available with the `develop` mode of
169+
reason, the coverage script builds the package in `develop` mode of
171170
`setup.py`.
172171

173172
The coverage results for the C and Python sources will be printed to the
@@ -191,3 +190,52 @@ these steps:
191190
> ```
192191
> The error is related to the `tcl` package. You should uninstall the `tcl`
193192
> package to resolve the error.
193+
194+
## Error Reporting and Logging
195+
196+
The SyclInterface library responds to `DPCTL_VERBOSITY` environment variable that controls the severity level of errors printed to console.
197+
One can specify one of the following severity levels (in increasing order of severity): `warning` and `error`.
198+
199+
```bash
200+
export DPCTL_VERBOSITY=warning
201+
```
202+
203+
Messages of a given severity are shown not only in the console for that severity, but also for the higher severity. For example, the severity level `warning` will output severity errors for `error` and `warning` to the console.
204+
205+
### Optional use of the Google logging library (glog)
206+
207+
Dpctl's error handler for libsyclinterface can be optionally configured to use [glog](https://github.com/google/glog). To use glog, follow the following steps:
208+
209+
1. Install glog package of the latest version (0.5.0)
210+
211+
```bash
212+
conda install glog
213+
```
214+
2. Build dpctl with glog support
215+
216+
```bash
217+
python scripts/build_locally.py --oneapi --glog
218+
```
219+
220+
3. Use `dpctl._diagnostics.syclinterface_diagnostics(verbosity="warning", log_dir=None)` context manager to switch library diagnostics on for a block of Python code.
221+
Use `DPCTLService_InitLogger` and `DPCTLService_ShutdownLogger` library C functions during library development to initialize the Google's logging library and de-initialize accordingly
222+
223+
```python
224+
from dpctl._diagnostics import syclinterface_diagnostics
225+
import dpctl
226+
227+
with syclinterface_diagnostics():
228+
code
229+
```
230+
231+
```c
232+
DPCTLService_InitLogger(const char *app_name, const char *log_dir);
233+
DPCTLService_ShutdownLogger();
234+
```
235+
236+
- `*app_name` - name of the executable file (prefix for logs of various levels).
237+
- `*log_dir` - directory path for writing log files. Specifying `NULL` results in logging to ``std::cerr``.
238+
239+
> **_NOTE:_**
240+
>
241+
> If `InitGoogleLogging` is not called before first use of glog, the library will self-initialize to `logtostderr` mode and log files will not be generated.

dpctl/_diagnostics.pyx

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Data Parallel Control (dpctl)
2+
#
3+
# Copyright 2020-2021 Intel Corporation
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
# distutils: language = c++
18+
# cython: language_level=3
19+
# cython: linetrace=True
20+
21+
""" Implements developer utilities.
22+
"""
23+
import contextlib
24+
import os
25+
26+
27+
cdef extern from "syclinterface/dpctl_service.h":
28+
cdef void DPCTLService_InitLogger(const char *, const char *)
29+
cdef void DPCTLService_ShutdownLogger()
30+
31+
32+
def _init_logger(log_dir=None):
33+
"""Initialize logger to use given directory to save logs.
34+
35+
The call has no effect if `dpctl` was not built to use logger.
36+
"""
37+
cdef bytes p = b""
38+
cdef const char *app_name = "dpctl"
39+
cdef char *ld_cstr = NULL
40+
if log_dir:
41+
if not os.path.exists(log_dir):
42+
raise ValueError(f"Path {log_dir} does not exist")
43+
if isinstance(log_dir, str):
44+
p = bytes(log_dir, "utf-8")
45+
else:
46+
p = bytes(log_dir)
47+
ld_cstr = <char *>p
48+
DPCTLService_InitLogger(app_name, ld_cstr)
49+
50+
51+
def _shutdown_logger():
52+
"""Finalize logger.
53+
54+
The call has no effect if `dpctl` was not built to use logger.
55+
"""
56+
DPCTLService_ShutdownLogger()
57+
58+
59+
@contextlib.contextmanager
60+
def syclinterface_diagnostics(verbosity="warning", log_dir=None):
61+
"""Context manager that activate verbosity of DPCTLSyclInterface
62+
function calls.
63+
"""
64+
_allowed_verbosity = ["warning", "error"]
65+
if not verbosity in _allowed_verbosity:
66+
raise ValueError(
67+
f"Verbosity argument not understood. "
68+
f"Permitted values are {_allowed_verbosity}"
69+
)
70+
_init_logger(log_dir=log_dir)
71+
_saved_verbosity = os.environ.get("DPCTL_VERBOSITY", None)
72+
os.environ["DPCTL_VERBOSITY"] = verbosity
73+
try:
74+
yield
75+
finally:
76+
_shutdown_logger()
77+
if _saved_verbosity:
78+
os.environ["DPCTL_VERBOSITY"] = _saved_verbosity
79+
else:
80+
del os.environ["DPCTL_VERBOSITY"]

dpctl/tests/test_service.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,25 @@ def test___version__():
107107
r"0|[1-9][0-9]*))?(\+.*)?$"
108108
)
109109
assert re.match(reg_expr, dpctl_ver) is not None
110+
111+
112+
def test_dev_utils():
113+
import tempfile
114+
115+
import dpctl._diagnostics as dd
116+
117+
ctx_mngr = dd.syclinterface_diagnostics
118+
119+
with ctx_mngr():
120+
dpctl.SyclDevice().parent_device
121+
with ctx_mngr(verbosity="error"):
122+
dpctl.SyclDevice().parent_device
123+
with pytest.raises(ValueError):
124+
with ctx_mngr(verbosity="blah"):
125+
dpctl.SyclDevice().parent_device
126+
with tempfile.TemporaryDirectory() as temp_dir:
127+
with ctx_mngr(log_dir=temp_dir):
128+
dpctl.SyclDevice().parent_device
129+
with pytest.raises(ValueError):
130+
with ctx_mngr(log_dir="/not_a_dir"):
131+
dpctl.SyclDevice().parent_device

libsyclinterface/CMakeLists.txt

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ option(DPCTL_BUILD_CAPI_TESTS
3838
"Build dpctl C API google tests"
3939
OFF
4040
)
41+
# Option to turn on logging support for dpctl C API
42+
option(DPCTL_ENABLE_GLOG
43+
"Enable the Google logging module"
44+
OFF
45+
)
4146

4247
# Minimum version requirement only when oneAPI dpcpp is used.
4348
if(DPCTL_DPCPP_FROM_ONEAPI)
@@ -166,12 +171,25 @@ target_include_directories(DPCTLSyclInterface
166171
${CMAKE_CURRENT_SOURCE_DIR}/helper/include/
167172
${IntelSycl_SYCL_INCLUDE_DIR}
168173
)
169-
170174
target_link_libraries(DPCTLSyclInterface
171-
PRIVATE ${IntelSycl_SYCL_LIBRARY}
172-
PRIVATE ${IntelSycl_OPENCL_LIBRARY}
175+
PRIVATE ${IntelSycl_SYCL_LIBRARY}
176+
PRIVATE ${IntelSycl_OPENCL_LIBRARY}
173177
)
174178

179+
if(DPCTL_ENABLE_GLOG)
180+
find_package(glog REQUIRED)
181+
182+
target_include_directories(DPCTLSyclInterface
183+
PRIVATE
184+
glog::glog
185+
)
186+
target_compile_definitions(DPCTLSyclInterface PRIVATE ENABLE_GLOG)
187+
target_link_libraries(DPCTLSyclInterface
188+
PRIVATE glog::glog
189+
)
190+
endif()
191+
192+
175193
include(GetProjectVersion)
176194
# the get_version function is defined in the GetProjectVersion module and
177195
# defines: VERSION, SEMVER, MAJOR, MINOR, PATCH. These variables are populated

libsyclinterface/helper/source/dpctl_error_handlers.cpp

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,12 @@
2424
//===----------------------------------------------------------------------===//
2525

2626
#include "dpctl_error_handlers.h"
27+
#include "dpctl_service.h"
2728
#include <cstring>
29+
#include <sstream>
30+
#ifdef ENABLE_GLOG
31+
#include <glog/logging.h>
32+
#endif
2833

2934
void DPCTL_AsyncErrorHandler::operator()(
3035
const cl::sycl::exception_list &exceptions)
@@ -59,6 +64,34 @@ int requested_verbosity_level(void)
5964

6065
return requested_level;
6166
}
67+
68+
void output_message(std::string ss_str, error_level error_type)
69+
{
70+
#ifdef ENABLE_GLOG
71+
switch (error_type) {
72+
case error_level::error:
73+
LOG(ERROR) << "[ERR] " << ss_str;
74+
break;
75+
case error_level::warning:
76+
LOG(WARNING) << "[WARN] " << ss_str;
77+
break;
78+
default:
79+
LOG(FATAL) << "[FATAL] " << ss_str;
80+
}
81+
#else
82+
switch (error_type) {
83+
case error_level::error:
84+
std::cerr << "[ERR] " << ss_str;
85+
break;
86+
case error_level::warning:
87+
std::cerr << "[WARN] " << ss_str;
88+
break;
89+
default:
90+
std::cerr << "[FATAL] " << ss_str;
91+
}
92+
#endif
93+
}
94+
6295
} // namespace
6396

6497
void error_handler(const std::exception &e,
@@ -70,9 +103,14 @@ void error_handler(const std::exception &e,
70103
int requested_level = requested_verbosity_level();
71104
int error_level = static_cast<int>(error_type);
72105

73-
if (requested_level >= error_level) {
74-
std::cerr << e.what() << " in " << func_name << " at " << file_name
75-
<< ":" << line_num << std::endl;
106+
bool to_output = requested_level >= error_level;
107+
108+
if (to_output) {
109+
std::stringstream ss;
110+
ss << e.what() << " in " << func_name << " at " << file_name << ":"
111+
<< line_num << std::endl;
112+
113+
output_message(ss.str(), error_type);
76114
}
77115
}
78116

@@ -85,8 +123,13 @@ void error_handler(const std::string &what,
85123
int requested_level = requested_verbosity_level();
86124
int error_level = static_cast<int>(error_type);
87125

88-
if (requested_level >= error_level) {
89-
std::cerr << what << " In " << func_name << " at " << file_name << ":"
90-
<< line_num << std::endl;
126+
bool to_output = requested_level >= error_level;
127+
128+
if (to_output) {
129+
std::stringstream ss;
130+
ss << what << " in " << func_name << " at " << file_name << ":"
131+
<< line_num << std::endl;
132+
133+
output_message(ss.str(), error_type);
91134
}
92135
}

libsyclinterface/include/dpctl_service.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,22 @@ DPCTL_C_EXTERN_C_BEGIN
4343
DPCTL_API
4444
__dpctl_give const char *DPCTLService_GetDPCPPVersion(void);
4545

46+
/*!
47+
* @brief Initialize logger if compiled to use logger, no-op otherwise.
48+
*
49+
* @param app_name C-string for application name reflected in the log.
50+
* @paral log_dir C-string for directory where log files are placed.
51+
* @ingroup Service
52+
*/
53+
DPCTL_API
54+
void DPCTLService_InitLogger(const char *app_name, const char *log_dir);
55+
56+
/*!
57+
* @brief Finilize logger if enabled, no-op otherwise.
58+
*
59+
* @ingroup Service
60+
*/
61+
DPCTL_API
62+
void DPCTLService_ShutdownLogger(void);
63+
4664
DPCTL_C_EXTERN_C_END

libsyclinterface/source/dpctl_service.cpp

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,54 @@
2626
#include "dpctl_service.h"
2727
#include "Config/dpctl_config.h"
2828

29-
#include "../helper/include/dpctl_string_utils.hpp"
29+
#include "dpctl_string_utils.hpp"
3030
#include <algorithm>
3131
#include <cstring>
3232
#include <iostream>
33+
#ifdef ENABLE_GLOG
34+
#include <filesystem>
35+
#include <glog/logging.h>
36+
#endif
3337

3438
__dpctl_give const char *DPCTLService_GetDPCPPVersion(void)
3539
{
3640
std::string version = DPCTL_DPCPP_VERSION;
3741
return dpctl::helper::cstring_from_string(version);
3842
}
43+
44+
#ifdef ENABLE_GLOG
45+
46+
void DPCTLService_InitLogger(const char *app_name, const char *log_dir)
47+
{
48+
google::InitGoogleLogging(app_name);
49+
google::InstallFailureSignalHandler();
50+
51+
if (log_dir) {
52+
namespace fs = std::filesystem;
53+
const fs::path path(log_dir);
54+
std::error_code ec;
55+
56+
if (fs::is_directory(path, ec)) {
57+
google::EnableLogCleaner(0);
58+
FLAGS_log_dir = log_dir;
59+
}
60+
}
61+
else {
62+
FLAGS_colorlogtostderr = true;
63+
FLAGS_stderrthreshold = google::FATAL;
64+
FLAGS_logtostderr = 1;
65+
}
66+
}
67+
68+
void DPCTLService_ShutdownLogger(void)
69+
{
70+
google::ShutdownGoogleLogging();
71+
}
72+
73+
#else
74+
void DPCTLService_InitLogger([[maybe_unused]] const char *app_name,
75+
[[maybe_unused]] const char *log_dir){};
76+
77+
void DPCTLService_ShutdownLogger(void){};
78+
79+
#endif

0 commit comments

Comments
 (0)