NVTX++  3.0
C++ convenience wrappers for NVTX.
nvtx3.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2019 Jacob Hemstad
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 #if defined(NVTX3_MINOR_VERSION) and NVTX3_MINOR_VERSION < 0
19 #error \
20  "Trying to #include NVTX version 3 in a source file where an older NVTX version has already been included. If you are not directly using NVTX (the NVIDIA Tools Extension library), you are getting this error because libraries you are using have included different versions of NVTX. Suggested solutions are: (1) reorder #includes so the newest NVTX version is included first, (2) avoid using the conflicting libraries in the same .c/.cpp file, or (3) update the library using the older NVTX version to use the newer version instead."
21 #endif
22 
32 #define NVTX3_MINOR_VERSION 0
33 
34 #include <nvToolsExt.h>
35 
36 #include <string>
37 
511 #if __cpp_constexpr >= 201304L
512 #define NVTX3_RELAXED_CONSTEXPR constexpr
513 #else
514 #define NVTX3_RELAXED_CONSTEXPR
515 #endif
516 
517 namespace nvtx3 {
518 namespace detail {
519 
528 template <typename T>
529 constexpr auto has_name_member() noexcept -> decltype(T::name, bool()) {
530  return (std::is_same<char const*,
531  typename std::decay<decltype(T::name)>::type>::value or
532  std::is_same<wchar_t const*,
533  typename std::decay<decltype(T::name)>::type>::value);
534 }
535 } // namespace detail
536 
591 class domain {
592  public:
593  domain(domain const&) = delete;
594  domain& operator=(domain const&) = delete;
595  domain(domain&&) = delete;
596  domain& operator=(domain&&) = delete;
597 
642  template <typename DomainName>
643  static domain const& get() {
644  static_assert(detail::has_name_member<DomainName>(),
645  "Type used to identify a domain must contain a name member of"
646  "type const char* or const wchar_t*");
647  static domain const d{DomainName::name};
648  return d;
649  }
650 
657  operator nvtxDomainHandle_t() const noexcept { return _domain; }
658 
670  struct global {};
671 
672  private:
681  explicit domain(char const* name) noexcept
682  : _domain{nvtxDomainCreateA(name)} {}
683 
692  explicit domain(wchar_t const* name) noexcept
693  : _domain{nvtxDomainCreateW(name)} {}
694 
703  explicit domain(std::string const& name) noexcept : domain{name.c_str()} {}
704 
713  explicit domain(std::wstring const& name) noexcept : domain{name.c_str()} {}
714 
723  domain() = default;
724 
729  ~domain() noexcept { nvtxDomainDestroy(_domain); }
730 
731  private:
732  nvtxDomainHandle_t const _domain{};
733 };
734 
748 template <>
749 inline domain const& domain::get<domain::global>() {
750  static domain const d{};
751  return d;
752 }
753 
759 struct rgb {
761  using component_type = uint8_t;
762 
773  constexpr rgb(component_type red_, component_type green_,
774  component_type blue_) noexcept
775  : red{red_}, green{green_}, blue{blue_} {}
776 
777  component_type const red{};
778  component_type const green{};
779  component_type const blue{};
780 };
781 
787 struct argb final : rgb {
800  constexpr argb(component_type alpha_, component_type red_,
801  component_type green_, component_type blue_) noexcept
802  : rgb{red_, green_, blue_}, alpha{alpha_} {}
803 
804  component_type const alpha{};
805 };
806 
816 class color {
817  public:
819  using value_type = uint32_t;
820 
838  constexpr explicit color(value_type hex_code) noexcept : _value{hex_code} {}
839 
846  constexpr color(argb argb) noexcept
847  : color{from_bytes_msb_to_lsb(argb.alpha, argb.red, argb.green,
848  argb.blue)} {}
849 
858  constexpr color(rgb rgb) noexcept
859  : color{from_bytes_msb_to_lsb(0xFF, rgb.red, rgb.green, rgb.blue)} {}
860 
865  constexpr value_type get_value() const noexcept { return _value; }
866 
871  constexpr nvtxColorType_t get_type() const noexcept { return _type; }
872 
873  color() = delete;
874  ~color() = default;
875  color(color const&) = default;
876  color& operator=(color const&) = default;
877  color(color&&) = default;
878  color& operator=(color&&) = default;
879 
880  private:
886  constexpr static value_type from_bytes_msb_to_lsb(uint8_t byte3,
887  uint8_t byte2,
888  uint8_t byte1,
889  uint8_t byte0) noexcept {
890  return uint32_t{byte3} << 24 | uint32_t{byte2} << 16 |
891  uint32_t{byte1} << 8 | uint32_t{byte0};
892  }
893 
894  value_type const _value{};
895  nvtxColorType_t const _type{NVTX_COLOR_ARGB};
896 };
897 
919 class category {
920  public:
922  using id_type = uint32_t;
923 
933  constexpr explicit category(id_type id) noexcept : id_{id} {}
934 
939  constexpr id_type get_id() const noexcept { return id_; }
940 
941  category() = delete;
942  ~category() = default;
943  category(category const&) = default;
944  category& operator=(category const&) = default;
945  category(category&&) = default;
946  category& operator=(category&&) = default;
947 
948  private:
949  id_type const id_{};
950 };
951 
1001 template <typename D = domain::global>
1002 class named_category final : public category {
1003  public:
1038  template <typename C>
1039  static named_category<D> const& get() noexcept {
1040  static_assert(detail::has_name_member<C>(),
1041  "Type used to name a category must contain a name member.");
1042  static named_category<D> const category{C::id, C::name};
1043  return category;
1044  }
1055  named_category(id_type id, char const* name) noexcept : category{id} {
1056  nvtxDomainNameCategoryA(domain::get<D>(), get_id(), name);
1057  };
1058 
1069  named_category(id_type id, wchar_t const* name) noexcept : category{id} {
1070  nvtxDomainNameCategoryW(domain::get<D>(), get_id(), name);
1071  };
1072 };
1073 
1120 template <typename D = domain::global>
1122  public:
1156  template <typename M>
1157  static registered_message<D> const& get() noexcept {
1158  static registered_message<D> const registered_message{M::message};
1159  return registered_message;
1160  }
1161 
1173  explicit registered_message(char const* msg) noexcept
1174  : handle_{nvtxDomainRegisterStringA(domain::get<D>(), msg)} {}
1175 
1187  explicit registered_message(std::string const& msg) noexcept
1188  : registered_message{msg.c_str()} {}
1189 
1201  explicit registered_message(wchar_t const* msg) noexcept
1202  : handle_{nvtxDomainRegisterStringW(domain::get<D>(), msg)} {}
1203 
1215  explicit registered_message(std::wstring const& msg) noexcept
1216  : registered_message{msg.c_str()} {}
1217 
1222  nvtxStringHandle_t get_handle() const noexcept { return handle_; }
1223 
1224  registered_message() = delete;
1225  ~registered_message() = default;
1226  registered_message(registered_message const&) = default;
1227  registered_message& operator=(registered_message const&) = default;
1229  registered_message& operator=(registered_message&&) = default;
1230 
1231  private:
1232  nvtxStringHandle_t const handle_{};
1233 };
1235 
1273 class message {
1274  public:
1275  using value_type = nvtxMessageValue_t;
1276 
1282  NVTX3_RELAXED_CONSTEXPR message(char const* msg) noexcept
1283  : type_{NVTX_MESSAGE_TYPE_ASCII} {
1284  value_.ascii = msg;
1285  }
1286 
1292  message(std::string const& msg) noexcept : message{msg.c_str()} {}
1293 
1302  message(std::string&&) = delete;
1303 
1309  NVTX3_RELAXED_CONSTEXPR message(wchar_t const* msg) noexcept
1310  : type_{NVTX_MESSAGE_TYPE_UNICODE} {
1311  value_.unicode = msg;
1312  }
1313 
1319  message(std::wstring const& msg) noexcept : message{msg.c_str()} {}
1320 
1329  message(std::wstring&&) = delete;
1330 
1339  template <typename D>
1341  : type_{NVTX_MESSAGE_TYPE_REGISTERED} {
1342  value_.registered = msg.get_handle();
1343  }
1344 
1349  NVTX3_RELAXED_CONSTEXPR value_type get_value() const noexcept {
1350  return value_;
1351  }
1352 
1357  NVTX3_RELAXED_CONSTEXPR nvtxMessageType_t get_type() const noexcept {
1358  return type_;
1359  }
1360 
1361  private:
1362  nvtxMessageType_t const type_{};
1363  nvtxMessageValue_t value_{};
1364 };
1365 
1383 class payload {
1384  public:
1385  using value_type = typename nvtxEventAttributes_v2::payload_t;
1386 
1392  NVTX3_RELAXED_CONSTEXPR explicit payload(int64_t value) noexcept
1393  : type_{NVTX_PAYLOAD_TYPE_INT64}, value_{} {
1394  value_.llValue = value;
1395  }
1396 
1402  NVTX3_RELAXED_CONSTEXPR explicit payload(int32_t value) noexcept
1403  : type_{NVTX_PAYLOAD_TYPE_INT32}, value_{} {
1404  value_.iValue = value;
1405  }
1406 
1412  NVTX3_RELAXED_CONSTEXPR explicit payload(uint64_t value) noexcept
1413  : type_{NVTX_PAYLOAD_TYPE_UNSIGNED_INT64}, value_{} {
1414  value_.ullValue = value;
1415  }
1416 
1422  NVTX3_RELAXED_CONSTEXPR explicit payload(uint32_t value) noexcept
1423  : type_{NVTX_PAYLOAD_TYPE_UNSIGNED_INT32}, value_{} {
1424  value_.uiValue = value;
1425  }
1426 
1433  NVTX3_RELAXED_CONSTEXPR explicit payload(float value) noexcept
1434  : type_{NVTX_PAYLOAD_TYPE_FLOAT}, value_{} {
1435  value_.fValue = value;
1436  }
1437 
1444  NVTX3_RELAXED_CONSTEXPR explicit payload(double value) noexcept
1445  : type_{NVTX_PAYLOAD_TYPE_DOUBLE}, value_{} {
1446  value_.dValue = value;
1447  }
1448 
1453  NVTX3_RELAXED_CONSTEXPR value_type get_value() const noexcept {
1454  return value_;
1455  }
1456 
1461  NVTX3_RELAXED_CONSTEXPR nvtxPayloadType_t get_type() const noexcept {
1462  return type_;
1463  }
1464 
1465  private:
1466  nvtxPayloadType_t const type_;
1467  value_type value_;
1468 };
1469 
1532  public:
1533  using value_type = nvtxEventAttributes_t;
1534 
1539  constexpr event_attributes() noexcept
1540  : attributes_{
1541  NVTX_VERSION, // version
1542  sizeof(nvtxEventAttributes_t), // size
1543  0, // category
1544  NVTX_COLOR_UNKNOWN, // color type
1545  0, // color value
1546  NVTX_PAYLOAD_UNKNOWN, // payload type
1547  {}, // payload value (union)
1548  NVTX_MESSAGE_UNKNOWN, // message type
1549  {} // message value (union)
1550  } {}
1551 
1559  template <typename... Args>
1561  category const& c, Args const&... args) noexcept
1562  : event_attributes(args...) {
1563  attributes_.category = c.get_id();
1564  }
1565 
1573  template <typename... Args>
1575  color const& c, Args const&... args) noexcept
1576  : event_attributes(args...) {
1577  attributes_.color = c.get_value();
1578  attributes_.colorType = c.get_type();
1579  }
1580 
1588  template <typename... Args>
1590  payload const& p, Args const&... args) noexcept
1591  : event_attributes(args...) {
1592  attributes_.payload = p.get_value();
1593  attributes_.payloadType = p.get_type();
1594  }
1595 
1603  template <typename... Args>
1605  message const& m, Args const&... args) noexcept
1606  : event_attributes(args...) {
1607  attributes_.message = m.get_value();
1608  attributes_.messageType = m.get_type();
1609  }
1610 
1611  ~event_attributes() = default;
1612  event_attributes(event_attributes const&) = default;
1613  event_attributes& operator=(event_attributes const&) = default;
1614  event_attributes(event_attributes&&) = default;
1615  event_attributes& operator=(event_attributes&&) = default;
1616 
1621  constexpr value_type const* get() const noexcept { return &attributes_; }
1622 
1623  private:
1624  value_type attributes_{};
1625 };
1626 
1674 template <class D = domain::global>
1676  public:
1692  explicit domain_thread_range(event_attributes const& attr) noexcept {
1693  nvtxDomainRangePushEx(domain::get<D>(), attr.get());
1694  }
1695 
1723  template <typename First, typename... Args,
1724  typename = typename std::enable_if<not std::is_same<
1725  event_attributes, typename std::decay<First>>::value>>
1726  explicit domain_thread_range(First const& first, Args const&... args) noexcept
1727  : domain_thread_range{event_attributes{first, args...}} {}
1728 
1734  domain_thread_range() : domain_thread_range{event_attributes{}} {}
1735 
1736  domain_thread_range(domain_thread_range const&) = delete;
1737  domain_thread_range& operator=(domain_thread_range const&) = delete;
1739  domain_thread_range& operator=(domain_thread_range&&) = delete;
1740 
1744  ~domain_thread_range() noexcept { nvtxDomainRangePop(domain::get<D>()); }
1745 };
1746 
1752 
1772 template <typename D = domain::global>
1774  public:
1780  explicit domain_process_range(event_attributes const& attr) noexcept
1781  : range_id_{nvtxDomainRangeStartEx(domain::get<D>(), attr.get())} {}
1782 
1789  template <typename First, typename... Args,
1790  typename = typename std::enable_if<not std::is_same<
1791  event_attributes, typename std::decay<First>>::value>>
1792  explicit domain_process_range(First const& first,
1793  Args const&... args) noexcept
1794  : domain_process_range{event_attributes{first, args...}} {}
1795 
1800  constexpr domain_process_range() noexcept
1801  : domain_process_range{event_attributes{}} {}
1802 
1808  if (not moved_from_) {
1809  nvtxRangeEnd(range_id_);
1810  }
1811  }
1812 
1813  domain_process_range(domain_process_range const&) = delete;
1814  domain_process_range& operator=(domain_process_range const&) = delete;
1815 
1816  domain_process_range(domain_process_range&& other) noexcept
1817  : range_id_{other.range_id_} {
1818  other.moved_from_ = true;
1819  }
1820 
1821  domain_process_range& operator=(domain_process_range&& other) noexcept {
1822  range_id_ = other.range_id_;
1823  other.moved_from_ = true;
1824  }
1825 
1826  private:
1827  nvtxRangeId_t range_id_;
1828  bool moved_from_{false};
1830 };
1834 
1840 
1862 template <typename D = nvtx3::domain::global>
1863 inline void mark(event_attributes const& attr) noexcept {
1864  nvtxDomainMarkEx(domain::get<D>(), attr.get());
1865 }
1866 
1867 } // namespace nvtx3
1868 
1897 #define NVTX3_FUNC_RANGE_IN(D) \
1898  static ::nvtx3::registered_message<D> const nvtx3_func_name__{__func__}; \
1899  static ::nvtx3::event_attributes const nvtx3_func_attr__{nvtx3_func_name__}; \
1900  ::nvtx3::domain_thread_range<D> const nvtx3_range__{nvtx3_func_attr__};
1901 
1924 #define NVTX3_FUNC_RANGE() NVTX3_FUNC_RANGE_IN(::nvtx3::domain::global)
NVTX3_RELAXED_CONSTEXPR value_type get_value() const noexcept
Return the union holding the value of the payload.
Definition: nvtx3.hpp:1453
registered_message(char const *msg) noexcept
Constructs a registered_message from the specified msg string.
Definition: nvtx3.hpp:1173
registered_message(std::string const &msg) noexcept
Constructs a registered_message from the specified msg string.
Definition: nvtx3.hpp:1187
NVTX3_RELAXED_CONSTEXPR message(wchar_t const *msg) noexcept
Construct a message whose contents are specified by msg.
Definition: nvtx3.hpp:1309
constexpr auto has_name_member() noexcept-> decltype(T::name, bool())
Verifies if a type T contains a member T::name of type const char* or const wchar_t*.
Definition: nvtx3.hpp:529
void mark(event_attributes const &attr) noexcept
Annotates an instantaneous point in time with the attributes specified by attr.
Definition: nvtx3.hpp:1863
NVTX3_RELAXED_CONSTEXPR event_attributes(message const &m, Args const &...args) noexcept
Variadic constructor where the first argument is a message.
Definition: nvtx3.hpp:1604
domain_process_range(First const &first, Args const &...args) noexcept
Construct a new domain process range object.
Definition: nvtx3.hpp:1792
registered_message(std::wstring const &msg) noexcept
Constructs a registered_message from the specified msg string.
Definition: nvtx3.hpp:1215
NVTX3_RELAXED_CONSTEXPR payload(int32_t value) noexcept
Construct a payload from a signed, 4 byte integer.
Definition: nvtx3.hpp:1402
NVTX3_RELAXED_CONSTEXPR payload(int64_t value) noexcept
Construct a payload from a signed, 8 byte integer.
Definition: nvtx3.hpp:1392
~domain_thread_range() noexcept
Destroy the domain_thread_range, ending the NVTX range event.
Definition: nvtx3.hpp:1744
Object for intra-domain grouping of NVTX events.
Definition: nvtx3.hpp:919
Tag type for the "global" NVTX domain.
Definition: nvtx3.hpp:670
domain_thread_range(First const &first, Args const &...args) noexcept
Constructs a domain_thread_range from the constructor arguments of an event_attributes.
Definition: nvtx3.hpp:1726
NVTX3_RELAXED_CONSTEXPR payload(uint32_t value) noexcept
Construct a payload from an unsigned, 4 byte integer.
Definition: nvtx3.hpp:1422
constexpr domain_process_range() noexcept
Construct a new domain process range object.
Definition: nvtx3.hpp:1800
named_category(id_type id, wchar_t const *name) noexcept
Construct a category with the specified id and name.
Definition: nvtx3.hpp:1069
named_category(id_type id, char const *name) noexcept
Construct a category with the specified id and name.
Definition: nvtx3.hpp:1055
Indicates the value of the alpha, red, green, and blue color channels for an argb color code...
Definition: nvtx3.hpp:787
domain_process_range(event_attributes const &attr) noexcept
Construct a new domain process range object.
Definition: nvtx3.hpp:1780
nvtxStringHandle_t get_handle() const noexcept
Returns the registered message&#39;s handle.
Definition: nvtx3.hpp:1222
NVTX3_RELAXED_CONSTEXPR payload(float value) noexcept
Construct a payload from a single-precision floating point value.
Definition: nvtx3.hpp:1433
component_type const red
Red channel value.
Definition: nvtx3.hpp:777
component_type const blue
Blue channel value.
Definition: nvtx3.hpp:779
Represents a custom color that can be associated with an NVTX event via it&#39;s event_attributes.
Definition: nvtx3.hpp:816
A message registered with NVTX.
Definition: nvtx3.hpp:1121
NVTX3_RELAXED_CONSTEXPR event_attributes(payload const &p, Args const &...args) noexcept
Variadic constructor where the first argument is a payload.
Definition: nvtx3.hpp:1589
NVTX3_RELAXED_CONSTEXPR nvtxMessageType_t get_type() const noexcept
Return the type information about the value the union holds.
Definition: nvtx3.hpp:1357
NVTX3_RELAXED_CONSTEXPR payload(uint64_t value) noexcept
Construct a payload from an unsigned, 8 byte integer.
Definition: nvtx3.hpp:1412
A RAII object for creating a NVTX range local to a thread within a domain.
Definition: nvtx3.hpp:1675
A numerical value that can be associated with an NVTX event via its event_attributes.
Definition: nvtx3.hpp:1383
constexpr category(id_type id) noexcept
Construct a category with the specified id.
Definition: nvtx3.hpp:933
NVTX3_RELAXED_CONSTEXPR value_type get_value() const noexcept
Return the union holding the value of the message.
Definition: nvtx3.hpp:1349
registered_message(wchar_t const *msg) noexcept
Constructs a registered_message from the specified msg string.
Definition: nvtx3.hpp:1201
NVTX3_RELAXED_CONSTEXPR payload(double value) noexcept
Construct a payload from a double-precision floating point value.
Definition: nvtx3.hpp:1444
uint32_t value_type
Type used for the color&#39;s value.
Definition: nvtx3.hpp:819
constexpr nvtxColorType_t get_type() const noexcept
Return the NVTX color type of the color.
Definition: nvtx3.hpp:871
constexpr argb(component_type alpha_, component_type red_, component_type green_, component_type blue_) noexcept
Construct an argb with alpha, red, green, and blue channels specified by alpha_, red_, green_, and blue_, respectively.
Definition: nvtx3.hpp:800
domains allow for grouping NVTX events into a single scope to differentiate them from events in other...
Definition: nvtx3.hpp:591
constexpr color(rgb rgb) noexcept
Construct a color using the red, green, blue components in rgb.
Definition: nvtx3.hpp:858
constexpr id_type get_id() const noexcept
Returns the id of the category.
Definition: nvtx3.hpp:939
component_type const alpha
Alpha channel value.
Definition: nvtx3.hpp:804
Definition: nvtx3.hpp:517
A RAII object for creating a NVTX range within a domain that can be created and destroyed on differen...
Definition: nvtx3.hpp:1773
uint8_t component_type
Type used for component values.
Definition: nvtx3.hpp:761
domain_thread_range(event_attributes const &attr) noexcept
Construct a domain_thread_range with the specified event_attributes
Definition: nvtx3.hpp:1692
Allows associating a message string with an NVTX event via its EventAttributes.
Definition: nvtx3.hpp:1273
Describes the attributes of a NVTX event.
Definition: nvtx3.hpp:1531
~domain_process_range() noexcept
Destroy the domain_process_range ending the range.
Definition: nvtx3.hpp:1807
A category with an associated name string.
Definition: nvtx3.hpp:1002
constexpr value_type get_value() const noexcept
Returns the colors argb hex code.
Definition: nvtx3.hpp:865
constexpr rgb(component_type red_, component_type green_, component_type blue_) noexcept
Construct a rgb with red, green, and blue channels specified by red_, green_, and blue_...
Definition: nvtx3.hpp:773
constexpr color(value_type hex_code) noexcept
Constructs a color using the value provided by hex_code.
Definition: nvtx3.hpp:838
message(std::wstring const &msg) noexcept
Construct a message whose contents are specified by msg.
Definition: nvtx3.hpp:1319
domain_thread_range()
Default constructor creates a domain_thread_range with no message, color, payload, nor category.
Definition: nvtx3.hpp:1734
#define NVTX3_RELAXED_CONSTEXPR
Enables the use of constexpr when support for C++14 relaxed constexpr is present. ...
Definition: nvtx3.hpp:514
message(std::string const &msg) noexcept
Construct a message whose contents are specified by msg.
Definition: nvtx3.hpp:1292
Indicates the values of the red, green, blue color channels for a rgb color code. ...
Definition: nvtx3.hpp:759
NVTX3_RELAXED_CONSTEXPR nvtxPayloadType_t get_type() const noexcept
Return the information about the type the union holds.
Definition: nvtx3.hpp:1461
NVTX3_RELAXED_CONSTEXPR event_attributes(category const &c, Args const &...args) noexcept
Variadic constructor where the first argument is a category.
Definition: nvtx3.hpp:1560
component_type const green
Green channel value.
Definition: nvtx3.hpp:778
constexpr event_attributes() noexcept
Default constructor creates an event_attributes with no category, color, payload, nor message...
Definition: nvtx3.hpp:1539
uint32_t id_type
Type used for categorys integer id.
Definition: nvtx3.hpp:922
NVTX3_RELAXED_CONSTEXPR message(registered_message< D > const &msg) noexcept
Construct a message from a registered_message.
Definition: nvtx3.hpp:1340
NVTX3_RELAXED_CONSTEXPR event_attributes(color const &c, Args const &...args) noexcept
Variadic constructor where the first argument is a color.
Definition: nvtx3.hpp:1574
constexpr color(argb argb) noexcept
Construct a color using the alpha, red, green, blue components in argb.
Definition: nvtx3.hpp:846
NVTX3_RELAXED_CONSTEXPR message(char const *msg) noexcept
Construct a message whose contents are specified by msg.
Definition: nvtx3.hpp:1282