├── .clang-format ├── .gitignore ├── CMakeLists.txt ├── MANIFEST.md ├── README.md ├── apps └── CMakeLists.txt ├── bench └── bm_copy.py ├── cmake ├── Modules │ ├── CMakeParseArgumentsCopy.cmake │ └── targetConfig.cmake.in └── cmake_uninstall.cmake.in ├── docs ├── CMakeLists.txt ├── README.cuda ├── doxygen │ ├── CMakeLists.txt │ ├── Doxyfile │ ├── Doxyfile.in │ ├── doxyxml │ │ ├── __init__.py │ │ ├── base.py │ │ ├── doxyindex.py │ │ ├── generated │ │ │ ├── __init__.py │ │ │ ├── compound.py │ │ │ ├── compoundsuper.py │ │ │ ├── index.py │ │ │ └── indexsuper.py │ │ └── text.py │ ├── pydoc_macros.h │ └── update_pydoc.py └── img │ └── flowgraph_copy.png ├── examples ├── .gitignore ├── README ├── cuda_copy.grc ├── cuda_multiply_const.grc └── load.grc ├── grc ├── CMakeLists.txt ├── cuda.domain.yml ├── cuda_copy.block.yml ├── cuda_load.block.yml └── cuda_multiply_const_xx.block.yml ├── include └── gnuradio │ └── cuda │ ├── CMakeLists.txt │ ├── api.h │ ├── copy.h │ ├── cuda_block.h │ ├── cuda_buffer.h │ ├── cuda_error.h │ ├── load.h │ └── multiply_const.h ├── lib ├── CMakeLists.txt ├── copy_impl.cc ├── copy_impl.h ├── cuda_buffer.cc ├── cuda_error.cc ├── load.cu ├── load.cuh ├── load_impl.cc ├── load_impl.h ├── multiply_const.cu ├── multiply_const_impl.cc └── multiply_const_impl.h └── python └── cuda ├── .gitignore ├── CMakeLists.txt ├── __init__.py ├── bindings ├── CMakeLists.txt ├── README.md ├── bind_oot_file.py ├── copy_python.cc ├── docstrings │ ├── README.md │ ├── copy_pydoc_template.h │ ├── load_pydoc_template.h │ └── multiply_const_pydoc_template.h ├── header_utils.py ├── load_python.cc ├── multiply_const_python.cc └── python_bindings.cc ├── qa_copy.py ├── qa_load.py └── qa_multiply_const.py /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: LLVM 4 | AccessModifierOffset: -4 5 | AlignAfterOpenBracket: Align 6 | AlignConsecutiveAssignments: false 7 | AlignConsecutiveDeclarations: false 8 | AlignEscapedNewlinesLeft: true 9 | AlignOperands: true 10 | AlignTrailingComments: true 11 | AllowAllParametersOfDeclarationOnNextLine: true 12 | AllowShortBlocksOnASingleLine: false 13 | AllowShortCaseLabelsOnASingleLine: false 14 | AllowShortFunctionsOnASingleLine: All 15 | AllowShortIfStatementsOnASingleLine: false 16 | AllowShortLoopsOnASingleLine: false 17 | AlwaysBreakAfterDefinitionReturnType: None 18 | AlwaysBreakAfterReturnType: None 19 | AlwaysBreakBeforeMultilineStrings: false 20 | AlwaysBreakTemplateDeclarations: true 21 | BinPackArguments: false 22 | BinPackParameters: false 23 | BreakBeforeBraces: Custom 24 | BraceWrapping: 25 | AfterClass: true 26 | AfterControlStatement: false 27 | AfterEnum: false 28 | AfterFunction: true 29 | AfterNamespace: false 30 | AfterObjCDeclaration: false 31 | AfterStruct: false 32 | AfterUnion: false 33 | BeforeCatch: false 34 | BeforeElse: false 35 | IndentBraces: false 36 | BreakBeforeBinaryOperators: None 37 | BreakBeforeTernaryOperators: true 38 | BreakConstructorInitializersBeforeComma: false 39 | BreakAfterJavaFieldAnnotations: false 40 | BreakStringLiterals: true 41 | ColumnLimit: 90 42 | CommentPragmas: '^ IWYU pragma:' 43 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 44 | ConstructorInitializerIndentWidth: 4 45 | ContinuationIndentWidth: 4 46 | Cpp11BracedListStyle: false 47 | DerivePointerAlignment: false 48 | DisableFormat: false 49 | ExperimentalAutoDetectBinPacking: false 50 | ForEachMacros: 51 | - foreach 52 | - Q_FOREACH 53 | - BOOST_FOREACH 54 | IncludeCategories: 55 | - Regex: '^"(gnuradio)/' 56 | Priority: 1 57 | - Regex: '^<(gnuradio)/' 58 | Priority: 2 59 | - Regex: '^<(boost)/' 60 | Priority: 98 61 | - Regex: '^<[a-z]*>$' 62 | Priority: 99 63 | - Regex: '^".*"$' 64 | Priority: 0 65 | - Regex: '.*' 66 | Priority: 10 67 | 68 | IncludeIsMainRegex: '(Test)?$' 69 | IndentCaseLabels: false 70 | IndentWidth: 4 71 | IndentWrappedFunctionNames: false 72 | JavaScriptQuotes: Leave 73 | JavaScriptWrapImports: true 74 | KeepEmptyLinesAtTheStartOfBlocks: true 75 | MacroBlockBegin: '' 76 | MacroBlockEnd: '' 77 | MaxEmptyLinesToKeep: 2 78 | NamespaceIndentation: None 79 | ObjCBlockIndentWidth: 2 80 | ObjCSpaceAfterProperty: false 81 | ObjCSpaceBeforeProtocolList: true 82 | PenaltyBreakBeforeFirstCallParameter: 19 83 | PenaltyBreakComment: 300 84 | PenaltyBreakFirstLessLess: 120 85 | PenaltyBreakString: 1000 86 | PenaltyExcessCharacter: 1000000 87 | PenaltyReturnTypeOnItsOwnLine: 60 88 | PointerAlignment: Left 89 | ReflowComments: true 90 | SortIncludes: true 91 | SpaceAfterCStyleCast: false 92 | SpaceAfterTemplateKeyword: true 93 | SpaceBeforeAssignmentOperators: true 94 | SpaceBeforeParens: ControlStatements 95 | SpaceInEmptyParentheses: false 96 | SpacesBeforeTrailingComments: 1 97 | SpacesInAngles: false 98 | SpacesInContainerLiterals: true 99 | SpacesInCStyleCastParentheses: false 100 | SpacesInParentheses: false 101 | SpacesInSquareBrackets: false 102 | Standard: Cpp11 103 | TabWidth: 8 104 | UseTab: Never 105 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | **/.vscode 35 | build/ 36 | **/__pycache__/ 37 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2011-2020 Free Software Foundation, Inc. 2 | # 3 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 4 | # This file is a part of gr-cuda 5 | # 6 | # SPDX-License-Identifier: GPL-3.0-or-later 7 | # 8 | 9 | ######################################################################## 10 | # Project setup 11 | ######################################################################## 12 | cmake_minimum_required(VERSION 3.8) 13 | project(gr-cuda CXX C CUDA) 14 | enable_testing() 15 | 16 | # Install to PyBOMBS target prefix if defined 17 | if(DEFINED ENV{PYBOMBS_PREFIX}) 18 | set(CMAKE_INSTALL_PREFIX $ENV{PYBOMBS_PREFIX}) 19 | message(STATUS "PyBOMBS installed GNU Radio. Setting CMAKE_INSTALL_PREFIX to $ENV{PYBOMBS_PREFIX}") 20 | endif() 21 | 22 | # Select the release build type by default to get optimization flags 23 | if(NOT CMAKE_BUILD_TYPE) 24 | set(CMAKE_BUILD_TYPE "Release") 25 | message(STATUS "Build type not specified: defaulting to release.") 26 | endif(NOT CMAKE_BUILD_TYPE) 27 | set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "") 28 | 29 | # Make sure our local CMake Modules path comes first 30 | list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_SOURCE_DIR}/cmake/Modules) 31 | 32 | # Set the version information here 33 | set(VERSION_MAJOR 1) 34 | set(VERSION_API 0) 35 | set(VERSION_ABI 0) 36 | set(VERSION_PATCH 0) 37 | 38 | cmake_policy(SET CMP0011 NEW) 39 | 40 | # Enable generation of compile_commands.json for code completion engines 41 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 42 | 43 | ######################################################################## 44 | # Compiler specific setup 45 | ######################################################################## 46 | if((CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR 47 | CMAKE_CXX_COMPILER_ID STREQUAL "GNU") 48 | AND NOT WIN32) 49 | #http://gcc.gnu.org/wiki/Visibility 50 | set(CMAKE_CXX_VISIBILITY_PRESET hidden) 51 | endif() 52 | 53 | IF(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") 54 | SET(CMAKE_CXX_STANDARD 17) 55 | ELSEIF(CMAKE_CXX_COMPILER_ID MATCHES "Clang") 56 | SET(CMAKE_CXX_STANDARD 17) 57 | ELSEIF(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") 58 | SET(CMAKE_CXX_STANDARD 17) 59 | ELSE() 60 | message(WARNING "C++ standard could not be set because compiler is not GNU, Clang or MSVC.") 61 | ENDIF() 62 | 63 | IF(CMAKE_C_COMPILER_ID STREQUAL "GNU") 64 | SET(CMAKE_C_STANDARD 11) 65 | ELSEIF(CMAKE_C_COMPILER_ID MATCHES "Clang") 66 | SET(CMAKE_C_STANDARD 11) 67 | ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "MSVC") 68 | SET(CMAKE_C_STANDARD 11) 69 | ELSE() 70 | message(WARNING "C standard could not be set because compiler is not GNU, Clang or MSVC.") 71 | ENDIF() 72 | 73 | ######################################################################## 74 | # Install directories 75 | ######################################################################## 76 | include(FindPkgConfig) 77 | find_package(Gnuradio "3.10" REQUIRED) 78 | include(GrVersion) 79 | 80 | include(GrPlatform) #define LIB_SUFFIX 81 | 82 | if(NOT CMAKE_MODULES_DIR) 83 | set(CMAKE_MODULES_DIR lib${LIB_SUFFIX}/cmake) 84 | endif(NOT CMAKE_MODULES_DIR) 85 | 86 | set(GR_INCLUDE_DIR include/gnuradio/cuda) 87 | set(GR_CMAKE_DIR ${CMAKE_MODULES_DIR}/gnuradio-cuda) 88 | set(GR_PKG_DATA_DIR ${GR_DATA_DIR}/${CMAKE_PROJECT_NAME}) 89 | set(GR_PKG_DOC_DIR ${GR_DOC_DIR}/${CMAKE_PROJECT_NAME}) 90 | set(GR_PKG_CONF_DIR ${GR_CONF_DIR}/${CMAKE_PROJECT_NAME}/conf.d) 91 | set(GR_PKG_LIBEXEC_DIR ${GR_LIBEXEC_DIR}/${CMAKE_PROJECT_NAME}) 92 | 93 | ######################################################################## 94 | # On Apple only, set install name and use rpath correctly, if not already set 95 | ######################################################################## 96 | if(APPLE) 97 | if(NOT CMAKE_INSTALL_NAME_DIR) 98 | set(CMAKE_INSTALL_NAME_DIR 99 | ${CMAKE_INSTALL_PREFIX}/${GR_LIBRARY_DIR} CACHE 100 | PATH "Library Install Name Destination Directory" FORCE) 101 | endif(NOT CMAKE_INSTALL_NAME_DIR) 102 | if(NOT CMAKE_INSTALL_RPATH) 103 | set(CMAKE_INSTALL_RPATH 104 | ${CMAKE_INSTALL_PREFIX}/${GR_LIBRARY_DIR} CACHE 105 | PATH "Library Install RPath" FORCE) 106 | endif(NOT CMAKE_INSTALL_RPATH) 107 | if(NOT CMAKE_BUILD_WITH_INSTALL_RPATH) 108 | set(CMAKE_BUILD_WITH_INSTALL_RPATH ON CACHE 109 | BOOL "Do Build Using Library Install RPath" FORCE) 110 | endif(NOT CMAKE_BUILD_WITH_INSTALL_RPATH) 111 | endif(APPLE) 112 | 113 | ######################################################################## 114 | # Find gnuradio build dependencies 115 | ######################################################################## 116 | find_package(Doxygen) 117 | 118 | ######################################################################## 119 | # Setup doxygen option 120 | ######################################################################## 121 | if(DOXYGEN_FOUND) 122 | option(ENABLE_DOXYGEN "Build docs using Doxygen" ON) 123 | else(DOXYGEN_FOUND) 124 | option(ENABLE_DOXYGEN "Build docs using Doxygen" OFF) 125 | endif(DOXYGEN_FOUND) 126 | 127 | ######################################################################## 128 | # Create uninstall target 129 | ######################################################################## 130 | configure_file( 131 | ${CMAKE_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in 132 | ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake 133 | @ONLY) 134 | 135 | add_custom_target(uninstall 136 | ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake 137 | ) 138 | 139 | ######################################################################## 140 | # Add subdirectories 141 | ######################################################################## 142 | add_subdirectory(include/gnuradio/cuda) 143 | add_subdirectory(lib) 144 | add_subdirectory(apps) 145 | add_subdirectory(docs) 146 | # NOTE: manually update below to use GRC to generate C++ flowgraphs w/o python 147 | if(ENABLE_PYTHON) 148 | message(STATUS "PYTHON and GRC components are enabled") 149 | add_subdirectory(python/cuda) 150 | add_subdirectory(grc) 151 | else(ENABLE_PYTHON) 152 | message(STATUS "PYTHON and GRC components are disabled") 153 | endif(ENABLE_PYTHON) 154 | -------------------------------------------------------------------------------- /MANIFEST.md: -------------------------------------------------------------------------------- 1 | title: The CUDA OOT Module 2 | brief: Short description of gr-cuda 3 | tags: # Tags are arbitrary, but look at CGRAN what other authors are using 4 | - sdr 5 | author: 6 | - Author Name 7 | copyright_owner: 8 | - Copyright Owner 1 9 | license: 10 | gr_supported_version: # Put a comma separated list of supported GR versions here 11 | #repo: # Put the URL of the repository here, or leave blank for default 12 | #website: # If you have a separate project website, put it here 13 | #icon: # Put a URL to a square image here that will be used as an icon on CGRAN 14 | --- 15 | A longer, multi-line description of gr-cuda. 16 | You may use some *basic* Markdown here. 17 | If left empty, it will try to find a README file instead. 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gr-cuda 2 | 3 | CUDA Support for GNU Radio using the custom buffer changes introduced in GR 3.10. Custom buffers for CUDA-enabled hardware are provided that can be included in any OOT. This allows the work() or general_work() function of a block to have data provided in the input- and output- buffers that has already been transitioned to device memory so that data movement does not have to take place in the work() function itself. 4 | 5 | Simple CUDA flowgraph 6 | 7 | ## Acknowledgement 8 | 9 | This OOT is adapted/copied from the gr-cuda_buffer OOT work by Black Lynx, Inc. (https://github.com/BlackLynx-Inc/gr-cuda_buffer) and relies on the custom buffer feature developed by David Sorber and documented here: 10 | https://wiki.gnuradio.org/index.php/CustomBuffers 11 | 12 | ## Prerequisites 13 | 14 | 1. NVIDIA CUDA supported GPU 15 | 2. Installation of CUDA 16 | 3. GNU Radio >= 3.10.0.0 17 | 18 | ## Usage 19 | 20 | This OOT can be included in your OOT as follows 21 | 22 | ### ./CMakeLists.txt 23 | ```cmake 24 | project(gr-myoot CXX C CUDA) 25 | ``` 26 | 27 | ### ./lib/CMakeLists.txt 28 | 29 | 1. Find the exported CMake from gr-cuda as follows 30 | ```cmake 31 | find_package(gnuradio-cuda REQUIRED) 32 | ``` 33 | 34 | 2. Create a library to hold the CUDA specific code: 35 | 36 | ```cuda 37 | add_library(gnuradio-myoot-cu STATIC 38 | my_kernel.cu 39 | ) 40 | set_target_properties(gnuradio-myoot-cu PROPERTIES 41 | POSITION_INDEPENDENT_CODE ON 42 | CUDA_VISIBILITY_PRESET "hidden" 43 | CUDA_SEPARABLE_COMPILATION ON 44 | ) 45 | 46 | # Make a fat binary for supported architectures 47 | # Compile for supported archs; CMake workaround, see: https://stackoverflow.com/a/54505975/73878 48 | target_compile_options(gnuradio-myoot-cu PRIVATE "$<$:SHELL:-gencode arch=compute_60,code=sm_60>") 49 | target_compile_options(gnuradio-myoot-cu PRIVATE "$<$:SHELL:-gencode arch=compute_61,code=sm_61>") 50 | target_compile_options(gnuradio-myoot-cu PRIVATE "$<$:SHELL:-gencode arch=compute_62,code=sm_62>") 51 | target_compile_options(gnuradio-myoot-cu PRIVATE "$<$:SHELL:-gencode arch=compute_70,code=sm_70>") 52 | target_compile_options(gnuradio-myoot-cu PRIVATE "$<$:SHELL:-gencode arch=compute_72,code=sm_72>") 53 | target_compile_options(gnuradio-myoot-cu PRIVATE "$<$:SHELL:-gencode arch=compute_75,code=sm_75>") 54 | # target_compile_options(gnuradio-myoot-cu PRIVATE "$<$:SHELL:-gencode arch=compute_80,code=sm_80>") 55 | # target_compile_options(gnuradio-myoot-cu PRIVATE "$<$:SHELL:-gencode arch=compute_86,code=sm_86>") 56 | ``` 57 | 58 | 3. Link to gr-cuda 59 | 60 | The `target_link_libraries` statement should be changed to specify public linkage 61 | ```cmake 62 | target_link_libraries(gnuradio-myoot PUBLIC gnuradio::gnuradio-runtime gnuradio-cuda) 63 | ``` 64 | 65 | 4. Link to the custom CUDA code 66 | ```cmake 67 | target_link_libraries(gnuradio-myoot PRIVATE gnuradio-myoot-cu) 68 | ``` 69 | 70 | ## Creating a Block in an OOT with CUDA acceleration 71 | 72 | 1. Create a `.cu` file that will hold the CUDA kernel and wrapper and be compiled with `nvcc` and linked to the block 73 | 74 | See `multiply_const.cu` for an example 75 | 76 | 2. Use `gr_modtool` to create a block in your OOT 77 | 78 | See `multiply_const.h`, `multiply_const_impl.{cc,h}` 79 | 80 | 3. Set the io_signature to specify the custom buffer 81 | 82 | 3. Call the kernel wrapper inside the `work()` function 83 | 84 | -------------------------------------------------------------------------------- /apps/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Free Software Foundation, Inc. 2 | # 3 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 4 | # This file is a part of gr-cuda 5 | # 6 | # SPDX-License-Identifier: GPL-3.0-or-later 7 | # 8 | 9 | include(GrPython) 10 | 11 | GR_PYTHON_INSTALL( 12 | PROGRAMS 13 | DESTINATION bin 14 | ) 15 | -------------------------------------------------------------------------------- /bench/bm_copy.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | # 5 | # SPDX-License-Identifier: GPL-3.0 6 | # 7 | # GNU Radio Python Flow Graph 8 | # Title: Not titled yet 9 | # GNU Radio version: 3.9.0.0-git 10 | 11 | from gnuradio import blocks 12 | from gnuradio import gr 13 | from gnuradio import cuda 14 | from gnuradio.filter import firdes 15 | import sys 16 | import signal 17 | from argparse import ArgumentParser 18 | from gnuradio.eng_arg import eng_float, intx 19 | from gnuradio import eng_notation 20 | from gnuradio.fft import window 21 | import time 22 | 23 | class benchmark_copy(gr.top_block): 24 | 25 | def __init__(self, args): 26 | gr.top_block.__init__(self, "Benchmark Copy", catch_exceptions=True) 27 | 28 | ################################################## 29 | # Variables 30 | ################################################## 31 | nsamples = args.samples 32 | veclen = args.veclen 33 | self.actual_samples = actual_samples = int(nsamples / veclen) 34 | num_blocks = args.nblocks 35 | self.load = args.load 36 | self.no_cb = args.no_cb 37 | 38 | ################################################## 39 | # Blocks 40 | ################################################## 41 | copy_blocks = [] 42 | for i in range(num_blocks): 43 | copy_blocks.append( 44 | cuda.load( 45 | self.load, 46 | gr.sizeof_gr_complex * veclen, 47 | not self.no_cb) 48 | ) 49 | 50 | self.blocks_null_source_0 = blocks.null_source( 51 | gr.sizeof_gr_complex*veclen) 52 | self.blocks_null_sink_0 = blocks.null_sink( 53 | gr.sizeof_gr_complex*veclen) 54 | self.blocks_head_0 = blocks.head( 55 | gr.sizeof_gr_complex*veclen, actual_samples) 56 | 57 | ################################################## 58 | # Connections 59 | ################################################## 60 | self.connect((self.blocks_head_0, 0), (copy_blocks[0], 0)) 61 | self.connect((self.blocks_null_source_0, 0), (self.blocks_head_0, 0)) 62 | 63 | for i in range(1, num_blocks): 64 | self.connect((copy_blocks[i-1], 0), (copy_blocks[i], 0)) 65 | 66 | self.connect((copy_blocks[num_blocks-1], 0), 67 | (self.blocks_null_sink_0, 0)) 68 | 69 | 70 | def main(top_block_cls=benchmark_copy, options=None): 71 | 72 | parser = ArgumentParser(description='Run a flowgraph iterating over parameters for benchmarking') 73 | parser.add_argument('--rt_prio', help='enable realtime scheduling', action='store_true') 74 | parser.add_argument('--no_cb', help='disable custom buffers', action='store_true') 75 | parser.add_argument('--samples', type=int, default=1e9) 76 | parser.add_argument('--veclen', type=int, default=1) 77 | parser.add_argument('--nblocks', type=int, default=1) 78 | parser.add_argument('--load', type=int, default=100) 79 | 80 | args = parser.parse_args() 81 | print(args) 82 | 83 | if args.rt_prio and gr.enable_realtime_scheduling() != gr.RT_OK: 84 | print("Error: failed to enable real-time scheduling.") 85 | 86 | tb = top_block_cls(args) 87 | 88 | def sig_handler(sig=None, frame=None): 89 | tb.stop() 90 | tb.wait() 91 | sys.exit(0) 92 | 93 | signal.signal(signal.SIGINT, sig_handler) 94 | signal.signal(signal.SIGTERM, sig_handler) 95 | 96 | print("starting ...") 97 | startt = time.time() 98 | tb.start() 99 | 100 | tb.wait() 101 | endt = time.time() 102 | 103 | print(f'[PROFILE_TIME]{endt-startt}[PROFILE_TIME]') 104 | 105 | if __name__ == '__main__': 106 | main() 107 | -------------------------------------------------------------------------------- /cmake/Modules/CMakeParseArgumentsCopy.cmake: -------------------------------------------------------------------------------- 1 | # CMAKE_PARSE_ARGUMENTS( args...) 2 | # 3 | # CMAKE_PARSE_ARGUMENTS() is intended to be used in macros or functions for 4 | # parsing the arguments given to that macro or function. 5 | # It processes the arguments and defines a set of variables which hold the 6 | # values of the respective options. 7 | # 8 | # The argument contains all options for the respective macro, 9 | # i.e. keywords which can be used when calling the macro without any value 10 | # following, like e.g. the OPTIONAL keyword of the install() command. 11 | # 12 | # The argument contains all keywords for this macro 13 | # which are followed by one value, like e.g. DESTINATION keyword of the 14 | # install() command. 15 | # 16 | # The argument contains all keywords for this macro 17 | # which can be followed by more than one value, like e.g. the TARGETS or 18 | # FILES keywords of the install() command. 19 | # 20 | # When done, CMAKE_PARSE_ARGUMENTS() will have defined for each of the 21 | # keywords listed in , and 22 | # a variable composed of the given 23 | # followed by "_" and the name of the respective keyword. 24 | # These variables will then hold the respective value from the argument list. 25 | # For the keywords this will be TRUE or FALSE. 26 | # 27 | # All remaining arguments are collected in a variable 28 | # _UNPARSED_ARGUMENTS, this can be checked afterwards to see whether 29 | # your macro was called with unrecognized parameters. 30 | # 31 | # As an example here a my_install() macro, which takes similar arguments as the 32 | # real install() command: 33 | # 34 | # function(MY_INSTALL) 35 | # set(options OPTIONAL FAST) 36 | # set(oneValueArgs DESTINATION RENAME) 37 | # set(multiValueArgs TARGETS CONFIGURATIONS) 38 | # cmake_parse_arguments(MY_INSTALL "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) 39 | # ... 40 | # 41 | # Assume my_install() has been called like this: 42 | # my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub) 43 | # 44 | # After the cmake_parse_arguments() call the macro will have set the following 45 | # variables: 46 | # MY_INSTALL_OPTIONAL = TRUE 47 | # MY_INSTALL_FAST = FALSE (this option was not used when calling my_install() 48 | # MY_INSTALL_DESTINATION = "bin" 49 | # MY_INSTALL_RENAME = "" (was not used) 50 | # MY_INSTALL_TARGETS = "foo;bar" 51 | # MY_INSTALL_CONFIGURATIONS = "" (was not used) 52 | # MY_INSTALL_UNPARSED_ARGUMENTS = "blub" (no value expected after "OPTIONAL" 53 | # 54 | # You can the continue and process these variables. 55 | # 56 | # Keywords terminate lists of values, e.g. if directly after a one_value_keyword 57 | # another recognized keyword follows, this is interpreted as the beginning of 58 | # the new option. 59 | # E.g. my_install(TARGETS foo DESTINATION OPTIONAL) would result in 60 | # MY_INSTALL_DESTINATION set to "OPTIONAL", but MY_INSTALL_DESTINATION would 61 | # be empty and MY_INSTALL_OPTIONAL would be set to TRUE therefore. 62 | 63 | #============================================================================= 64 | # Copyright 2010 Alexander Neundorf 65 | # 66 | # Distributed under the OSI-approved BSD License (the "License"); 67 | # see accompanying file Copyright.txt for details. 68 | # 69 | # This software is distributed WITHOUT ANY WARRANTY; without even the 70 | # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 71 | # See the License for more information. 72 | #============================================================================= 73 | # (To distribute this file outside of CMake, substitute the full 74 | # License text for the above reference.) 75 | 76 | 77 | if(__CMAKE_PARSE_ARGUMENTS_INCLUDED) 78 | return() 79 | endif() 80 | set(__CMAKE_PARSE_ARGUMENTS_INCLUDED TRUE) 81 | 82 | 83 | function(CMAKE_PARSE_ARGUMENTS prefix _optionNames _singleArgNames _multiArgNames) 84 | # first set all result variables to empty/FALSE 85 | foreach(arg_name ${_singleArgNames} ${_multiArgNames}) 86 | set(${prefix}_${arg_name}) 87 | endforeach(arg_name) 88 | 89 | foreach(option ${_optionNames}) 90 | set(${prefix}_${option} FALSE) 91 | endforeach(option) 92 | 93 | set(${prefix}_UNPARSED_ARGUMENTS) 94 | 95 | set(insideValues FALSE) 96 | set(currentArgName) 97 | 98 | # now iterate over all arguments and fill the result variables 99 | foreach(currentArg ${ARGN}) 100 | list(FIND _optionNames "${currentArg}" optionIndex) # ... then this marks the end of the arguments belonging to this keyword 101 | list(FIND _singleArgNames "${currentArg}" singleArgIndex) # ... then this marks the end of the arguments belonging to this keyword 102 | list(FIND _multiArgNames "${currentArg}" multiArgIndex) # ... then this marks the end of the arguments belonging to this keyword 103 | 104 | if(${optionIndex} EQUAL -1 AND ${singleArgIndex} EQUAL -1 AND ${multiArgIndex} EQUAL -1) 105 | if(insideValues) 106 | if("${insideValues}" STREQUAL "SINGLE") 107 | set(${prefix}_${currentArgName} ${currentArg}) 108 | set(insideValues FALSE) 109 | elseif("${insideValues}" STREQUAL "MULTI") 110 | list(APPEND ${prefix}_${currentArgName} ${currentArg}) 111 | endif() 112 | else(insideValues) 113 | list(APPEND ${prefix}_UNPARSED_ARGUMENTS ${currentArg}) 114 | endif(insideValues) 115 | else() 116 | if(NOT ${optionIndex} EQUAL -1) 117 | set(${prefix}_${currentArg} TRUE) 118 | set(insideValues FALSE) 119 | elseif(NOT ${singleArgIndex} EQUAL -1) 120 | set(currentArgName ${currentArg}) 121 | set(${prefix}_${currentArgName}) 122 | set(insideValues "SINGLE") 123 | elseif(NOT ${multiArgIndex} EQUAL -1) 124 | set(currentArgName ${currentArg}) 125 | set(${prefix}_${currentArgName}) 126 | set(insideValues "MULTI") 127 | endif() 128 | endif() 129 | 130 | endforeach(currentArg) 131 | 132 | # propagate the result variables to the caller: 133 | foreach(arg_name ${_singleArgNames} ${_multiArgNames} ${_optionNames}) 134 | set(${prefix}_${arg_name} ${${prefix}_${arg_name}} PARENT_SCOPE) 135 | endforeach(arg_name) 136 | set(${prefix}_UNPARSED_ARGUMENTS ${${prefix}_UNPARSED_ARGUMENTS} PARENT_SCOPE) 137 | 138 | endfunction(CMAKE_PARSE_ARGUMENTS _options _singleArgs _multiArgs) 139 | -------------------------------------------------------------------------------- /cmake/Modules/targetConfig.cmake.in: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Free Software Foundation, Inc. 2 | # 3 | # This file is part of GNU Radio 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | # 7 | 8 | if(NOT PKG_CONFIG_FOUND) 9 | INCLUDE(FindPkgConfig) 10 | endif() 11 | PKG_CHECK_MODULES(PC_@TARGET@ gnuradio-cuda) 12 | 13 | FIND_PATH( 14 | @TARGET@_INCLUDE_DIRS 15 | NAMES gnuradio/cuda/api.h 16 | HINTS $ENV{@TARGET@_DIR}/include 17 | ${PC_@TARGET@_INCLUDEDIR} 18 | PATHS ${CMAKE_INSTALL_PREFIX}/include 19 | /usr/local/include 20 | /usr/include 21 | ) 22 | 23 | FIND_LIBRARY( 24 | @TARGET@_LIBRARIES 25 | NAMES gnuradio-cuda 26 | HINTS $ENV{@TARGET@_DIR}/lib 27 | ${PC_@TARGET@_LIBDIR} 28 | PATHS ${CMAKE_INSTALL_PREFIX}/lib 29 | ${CMAKE_INSTALL_PREFIX}/lib64 30 | /usr/local/lib 31 | /usr/local/lib64 32 | /usr/lib 33 | /usr/lib64 34 | ) 35 | 36 | INCLUDE(FindPackageHandleStandardArgs) 37 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(@TARGET@ DEFAULT_MSG @TARGET@_LIBRARIES @TARGET@_INCLUDE_DIRS) 38 | MARK_AS_ADVANCED(@TARGET@_LIBRARIES @TARGET@_INCLUDE_DIRS) 39 | 40 | 41 | include(CMakeFindDependencyMacro) 42 | 43 | set(target_deps "@TARGET_DEPENDENCIES@") 44 | foreach(dep IN LISTS target_deps) 45 | find_dependency(${dep}) 46 | endforeach() 47 | include("${CMAKE_CURRENT_LIST_DIR}/@TARGET@Targets.cmake") 48 | -------------------------------------------------------------------------------- /cmake/cmake_uninstall.cmake.in: -------------------------------------------------------------------------------- 1 | # http://www.vtk.org/Wiki/CMake_FAQ#Can_I_do_.22make_uninstall.22_with_CMake.3F 2 | 3 | IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 4 | MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") 5 | ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 6 | 7 | FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) 8 | STRING(REGEX REPLACE "\n" ";" files "${files}") 9 | FOREACH(file ${files}) 10 | MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") 11 | IF(EXISTS "$ENV{DESTDIR}${file}") 12 | EXEC_PROGRAM( 13 | "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" 14 | OUTPUT_VARIABLE rm_out 15 | RETURN_VALUE rm_retval 16 | ) 17 | IF(NOT "${rm_retval}" STREQUAL 0) 18 | MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") 19 | ENDIF(NOT "${rm_retval}" STREQUAL 0) 20 | ELSEIF(IS_SYMLINK "$ENV{DESTDIR}${file}") 21 | EXEC_PROGRAM( 22 | "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" 23 | OUTPUT_VARIABLE rm_out 24 | RETURN_VALUE rm_retval 25 | ) 26 | IF(NOT "${rm_retval}" STREQUAL 0) 27 | MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") 28 | ENDIF(NOT "${rm_retval}" STREQUAL 0) 29 | ELSE(EXISTS "$ENV{DESTDIR}${file}") 30 | MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") 31 | ENDIF(EXISTS "$ENV{DESTDIR}${file}") 32 | ENDFOREACH(file) 33 | -------------------------------------------------------------------------------- /docs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Free Software Foundation, Inc. 2 | # 3 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 4 | # This file is a part of gr-cuda 5 | # 6 | # SPDX-License-Identifier: GPL-3.0-or-later 7 | # 8 | 9 | ######################################################################## 10 | # Setup dependencies 11 | ######################################################################## 12 | find_package(Doxygen) 13 | 14 | ######################################################################## 15 | # Begin conditional configuration 16 | ######################################################################## 17 | if(ENABLE_DOXYGEN) 18 | 19 | ######################################################################## 20 | # Add subdirectories 21 | ######################################################################## 22 | add_subdirectory(doxygen) 23 | 24 | endif(ENABLE_DOXYGEN) 25 | -------------------------------------------------------------------------------- /docs/README.cuda: -------------------------------------------------------------------------------- 1 | This is the cuda-write-a-block package meant as a guide to building 2 | out-of-tree packages. To use the cuda blocks, the Python namespaces 3 | is in 'cuda', which is imported as: 4 | 5 | import cuda 6 | 7 | See the Doxygen documentation for details about the blocks available 8 | in this package. A quick listing of the details can be found in Python 9 | after importing by using: 10 | 11 | help(cuda) 12 | -------------------------------------------------------------------------------- /docs/doxygen/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Free Software Foundation, Inc. 2 | # 3 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 4 | # This file is a part of gr-cuda 5 | # 6 | # SPDX-License-Identifier: GPL-3.0-or-later 7 | # 8 | 9 | ######################################################################## 10 | # Create the doxygen configuration file 11 | ######################################################################## 12 | file(TO_NATIVE_PATH ${CMAKE_SOURCE_DIR} top_srcdir) 13 | file(TO_NATIVE_PATH ${CMAKE_BINARY_DIR} top_builddir) 14 | file(TO_NATIVE_PATH ${CMAKE_SOURCE_DIR} abs_top_srcdir) 15 | file(TO_NATIVE_PATH ${CMAKE_BINARY_DIR} abs_top_builddir) 16 | 17 | set(HAVE_DOT ${DOXYGEN_DOT_FOUND}) 18 | set(enable_html_docs YES) 19 | set(enable_latex_docs NO) 20 | set(enable_mathjax NO) 21 | set(enable_xml_docs YES) 22 | 23 | configure_file( 24 | ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in 25 | ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile 26 | @ONLY) 27 | 28 | set(BUILT_DIRS ${CMAKE_CURRENT_BINARY_DIR}/xml ${CMAKE_CURRENT_BINARY_DIR}/html) 29 | 30 | ######################################################################## 31 | # Make and install doxygen docs 32 | ######################################################################## 33 | add_custom_command( 34 | OUTPUT ${BUILT_DIRS} 35 | COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile 36 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 37 | COMMENT "Generating documentation with doxygen" 38 | ) 39 | 40 | add_custom_target(doxygen_target ALL DEPENDS ${BUILT_DIRS}) 41 | 42 | install(DIRECTORY ${BUILT_DIRS} DESTINATION ${GR_PKG_DOC_DIR}) 43 | -------------------------------------------------------------------------------- /docs/doxygen/doxyxml/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2010 Free Software Foundation, Inc. 3 | # 4 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 5 | # This file is a part of gr-cuda 6 | # 7 | # SPDX-License-Identifier: GPL-3.0-or-later 8 | # 9 | # 10 | """ 11 | Python interface to contents of doxygen xml documentation. 12 | 13 | Example use: 14 | See the contents of the example folder for the C++ and 15 | doxygen-generated xml used in this example. 16 | 17 | >>> # Parse the doxygen docs. 18 | >>> import os 19 | >>> this_dir = os.path.dirname(globals()['__file__']) 20 | >>> xml_path = this_dir + "/example/xml/" 21 | >>> di = DoxyIndex(xml_path) 22 | 23 | Get a list of all top-level objects. 24 | 25 | >>> print([mem.name() for mem in di.members()]) 26 | [u'Aadvark', u'aadvarky_enough', u'main'] 27 | 28 | Get all functions. 29 | 30 | >>> print([mem.name() for mem in di.in_category(DoxyFunction)]) 31 | [u'aadvarky_enough', u'main'] 32 | 33 | Check if an object is present. 34 | 35 | >>> di.has_member(u'Aadvark') 36 | True 37 | >>> di.has_member(u'Fish') 38 | False 39 | 40 | Get an item by name and check its properties. 41 | 42 | >>> aad = di.get_member(u'Aadvark') 43 | >>> print(aad.brief_description) 44 | Models the mammal Aadvark. 45 | >>> print(aad.detailed_description) 46 | Sadly the model is incomplete and cannot capture all aspects of an aadvark yet. 47 | 48 | This line is uninformative and is only to test line breaks in the comments. 49 | >>> [mem.name() for mem in aad.members()] 50 | [u'aadvarkness', u'print', u'Aadvark', u'get_aadvarkness'] 51 | >>> aad.get_member(u'print').brief_description 52 | u'Outputs the vital aadvark statistics.' 53 | 54 | """ 55 | 56 | from .doxyindex import DoxyIndex, DoxyFunction, DoxyParam, DoxyClass, DoxyFile, DoxyNamespace, DoxyGroup, DoxyFriend, DoxyOther 57 | 58 | def _test(): 59 | import os 60 | this_dir = os.path.dirname(globals()['__file__']) 61 | xml_path = this_dir + "/example/xml/" 62 | di = DoxyIndex(xml_path) 63 | # Get the Aadvark class 64 | aad = di.get_member('Aadvark') 65 | aad.brief_description 66 | import doctest 67 | return doctest.testmod() 68 | 69 | if __name__ == "__main__": 70 | _test() 71 | 72 | -------------------------------------------------------------------------------- /docs/doxygen/doxyxml/base.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2010 Free Software Foundation, Inc. 3 | # 4 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 5 | # This file is a part of gr-cuda 6 | # 7 | # SPDX-License-Identifier: GPL-3.0-or-later 8 | # 9 | # 10 | """ 11 | A base class is created. 12 | 13 | Classes based upon this are used to make more user-friendly interfaces 14 | to the doxygen xml docs than the generated classes provide. 15 | """ 16 | 17 | import os 18 | import pdb 19 | 20 | from xml.parsers.expat import ExpatError 21 | 22 | from .generated import compound 23 | 24 | 25 | class Base(object): 26 | 27 | class Duplicate(Exception): 28 | pass 29 | 30 | class NoSuchMember(Exception): 31 | pass 32 | 33 | class ParsingError(Exception): 34 | pass 35 | 36 | def __init__(self, parse_data, top=None): 37 | self._parsed = False 38 | self._error = False 39 | self._parse_data = parse_data 40 | self._members = [] 41 | self._dict_members = {} 42 | self._in_category = {} 43 | self._data = {} 44 | if top is not None: 45 | self._xml_path = top._xml_path 46 | # Set up holder of references 47 | else: 48 | top = self 49 | self._refs = {} 50 | self._xml_path = parse_data 51 | self.top = top 52 | 53 | @classmethod 54 | def from_refid(cls, refid, top=None): 55 | """ Instantiate class from a refid rather than parsing object. """ 56 | # First check to see if its already been instantiated. 57 | if top is not None and refid in top._refs: 58 | return top._refs[refid] 59 | # Otherwise create a new instance and set refid. 60 | inst = cls(None, top=top) 61 | inst.refid = refid 62 | inst.add_ref(inst) 63 | return inst 64 | 65 | @classmethod 66 | def from_parse_data(cls, parse_data, top=None): 67 | refid = getattr(parse_data, 'refid', None) 68 | if refid is not None and top is not None and refid in top._refs: 69 | return top._refs[refid] 70 | inst = cls(parse_data, top=top) 71 | if refid is not None: 72 | inst.refid = refid 73 | inst.add_ref(inst) 74 | return inst 75 | 76 | def add_ref(self, obj): 77 | if hasattr(obj, 'refid'): 78 | self.top._refs[obj.refid] = obj 79 | 80 | mem_classes = [] 81 | 82 | def get_cls(self, mem): 83 | for cls in self.mem_classes: 84 | if cls.can_parse(mem): 85 | return cls 86 | raise Exception(("Did not find a class for object '%s'." \ 87 | % (mem.get_name()))) 88 | 89 | def convert_mem(self, mem): 90 | try: 91 | cls = self.get_cls(mem) 92 | converted = cls.from_parse_data(mem, self.top) 93 | if converted is None: 94 | raise Exception('No class matched this object.') 95 | self.add_ref(converted) 96 | return converted 97 | except Exception as e: 98 | print(e) 99 | 100 | @classmethod 101 | def includes(cls, inst): 102 | return isinstance(inst, cls) 103 | 104 | @classmethod 105 | def can_parse(cls, obj): 106 | return False 107 | 108 | def _parse(self): 109 | self._parsed = True 110 | 111 | def _get_dict_members(self, cat=None): 112 | """ 113 | For given category a dictionary is returned mapping member names to 114 | members of that category. For names that are duplicated the name is 115 | mapped to None. 116 | """ 117 | self.confirm_no_error() 118 | if cat not in self._dict_members: 119 | new_dict = {} 120 | for mem in self.in_category(cat): 121 | if mem.name() not in new_dict: 122 | new_dict[mem.name()] = mem 123 | else: 124 | new_dict[mem.name()] = self.Duplicate 125 | self._dict_members[cat] = new_dict 126 | return self._dict_members[cat] 127 | 128 | def in_category(self, cat): 129 | self.confirm_no_error() 130 | if cat is None: 131 | return self._members 132 | if cat not in self._in_category: 133 | self._in_category[cat] = [mem for mem in self._members 134 | if cat.includes(mem)] 135 | return self._in_category[cat] 136 | 137 | def get_member(self, name, cat=None): 138 | self.confirm_no_error() 139 | # Check if it's in a namespace or class. 140 | bits = name.split('::') 141 | first = bits[0] 142 | rest = '::'.join(bits[1:]) 143 | member = self._get_dict_members(cat).get(first, self.NoSuchMember) 144 | # Raise any errors that are returned. 145 | if member in set([self.NoSuchMember, self.Duplicate]): 146 | raise member() 147 | if rest: 148 | return member.get_member(rest, cat=cat) 149 | return member 150 | 151 | def has_member(self, name, cat=None): 152 | try: 153 | mem = self.get_member(name, cat=cat) 154 | return True 155 | except self.NoSuchMember: 156 | return False 157 | 158 | def data(self): 159 | self.confirm_no_error() 160 | return self._data 161 | 162 | def members(self): 163 | self.confirm_no_error() 164 | return self._members 165 | 166 | def process_memberdefs(self): 167 | mdtss = [] 168 | for sec in self._retrieved_data.compounddef.sectiondef: 169 | mdtss += sec.memberdef 170 | # At the moment we lose all information associated with sections. 171 | # Sometimes a memberdef is in several sectiondef. 172 | # We make sure we don't get duplicates here. 173 | uniques = set([]) 174 | for mem in mdtss: 175 | converted = self.convert_mem(mem) 176 | pair = (mem.name, mem.__class__) 177 | if pair not in uniques: 178 | uniques.add(pair) 179 | self._members.append(converted) 180 | 181 | def retrieve_data(self): 182 | filename = os.path.join(self._xml_path, self.refid + '.xml') 183 | try: 184 | self._retrieved_data = compound.parse(filename) 185 | except ExpatError: 186 | print('Error in xml in file %s' % filename) 187 | self._error = True 188 | self._retrieved_data = None 189 | 190 | def check_parsed(self): 191 | if not self._parsed: 192 | self._parse() 193 | 194 | def confirm_no_error(self): 195 | self.check_parsed() 196 | if self._error: 197 | raise self.ParsingError() 198 | 199 | def error(self): 200 | self.check_parsed() 201 | return self._error 202 | 203 | def name(self): 204 | # first see if we can do it without processing. 205 | if self._parse_data is not None: 206 | return self._parse_data.name 207 | self.check_parsed() 208 | return self._retrieved_data.compounddef.name 209 | -------------------------------------------------------------------------------- /docs/doxygen/doxyxml/doxyindex.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2010 Free Software Foundation, Inc. 3 | # 4 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 5 | # This file is a part of gr-cuda 6 | # 7 | # SPDX-License-Identifier: GPL-3.0-or-later 8 | # 9 | # 10 | """ 11 | Classes providing more user-friendly interfaces to the doxygen xml 12 | docs than the generated classes provide. 13 | """ 14 | 15 | import os 16 | 17 | from .generated import index 18 | from .base import Base 19 | from .text import description 20 | 21 | class DoxyIndex(Base): 22 | """ 23 | Parses a doxygen xml directory. 24 | """ 25 | 26 | __module__ = "gnuradio.utils.doxyxml" 27 | 28 | def _parse(self): 29 | if self._parsed: 30 | return 31 | super(DoxyIndex, self)._parse() 32 | self._root = index.parse(os.path.join(self._xml_path, 'index.xml')) 33 | for mem in self._root.compound: 34 | converted = self.convert_mem(mem) 35 | # For files and namespaces we want the contents to be 36 | # accessible directly from the parent rather than having 37 | # to go through the file object. 38 | if self.get_cls(mem) == DoxyFile: 39 | if mem.name.endswith('.h'): 40 | self._members += converted.members() 41 | self._members.append(converted) 42 | elif self.get_cls(mem) == DoxyNamespace: 43 | self._members += converted.members() 44 | self._members.append(converted) 45 | else: 46 | self._members.append(converted) 47 | 48 | 49 | class DoxyCompMem(Base): 50 | 51 | 52 | kind = None 53 | 54 | def __init__(self, *args, **kwargs): 55 | super(DoxyCompMem, self).__init__(*args, **kwargs) 56 | 57 | @classmethod 58 | def can_parse(cls, obj): 59 | return obj.kind == cls.kind 60 | 61 | def set_descriptions(self, parse_data): 62 | bd = description(getattr(parse_data, 'briefdescription', None)) 63 | dd = description(getattr(parse_data, 'detaileddescription', None)) 64 | self._data['brief_description'] = bd 65 | self._data['detailed_description'] = dd 66 | 67 | def set_parameters(self, data): 68 | vs = [ddc.value for ddc in data.detaileddescription.content_] 69 | pls = [] 70 | for v in vs: 71 | if hasattr(v, 'parameterlist'): 72 | pls += v.parameterlist 73 | pis = [] 74 | for pl in pls: 75 | pis += pl.parameteritem 76 | dpis = [] 77 | for pi in pis: 78 | dpi = DoxyParameterItem(pi) 79 | dpi._parse() 80 | dpis.append(dpi) 81 | self._data['params'] = dpis 82 | 83 | 84 | class DoxyCompound(DoxyCompMem): 85 | pass 86 | 87 | class DoxyMember(DoxyCompMem): 88 | pass 89 | 90 | class DoxyFunction(DoxyMember): 91 | 92 | __module__ = "gnuradio.utils.doxyxml" 93 | 94 | kind = 'function' 95 | 96 | def _parse(self): 97 | if self._parsed: 98 | return 99 | super(DoxyFunction, self)._parse() 100 | self.set_descriptions(self._parse_data) 101 | self.set_parameters(self._parse_data) 102 | if not self._data['params']: 103 | # If the params weren't set by a comment then just grab the names. 104 | self._data['params'] = [] 105 | prms = self._parse_data.param 106 | for prm in prms: 107 | self._data['params'].append(DoxyParam(prm)) 108 | 109 | brief_description = property(lambda self: self.data()['brief_description']) 110 | detailed_description = property(lambda self: self.data()['detailed_description']) 111 | params = property(lambda self: self.data()['params']) 112 | 113 | Base.mem_classes.append(DoxyFunction) 114 | 115 | 116 | class DoxyParam(DoxyMember): 117 | 118 | __module__ = "gnuradio.utils.doxyxml" 119 | 120 | def _parse(self): 121 | if self._parsed: 122 | return 123 | super(DoxyParam, self)._parse() 124 | self.set_descriptions(self._parse_data) 125 | self._data['declname'] = self._parse_data.declname 126 | 127 | @property 128 | def description(self): 129 | descriptions = [] 130 | if self.brief_description: 131 | descriptions.append(self.brief_description) 132 | if self.detailed_description: 133 | descriptions.append(self.detailed_description) 134 | return '\n\n'.join(descriptions) 135 | 136 | brief_description = property(lambda self: self.data()['brief_description']) 137 | detailed_description = property(lambda self: self.data()['detailed_description']) 138 | name = property(lambda self: self.data()['declname']) 139 | 140 | class DoxyParameterItem(DoxyMember): 141 | """A different representation of a parameter in Doxygen.""" 142 | 143 | def _parse(self): 144 | if self._parsed: 145 | return 146 | super(DoxyParameterItem, self)._parse() 147 | names = [] 148 | for nl in self._parse_data.parameternamelist: 149 | for pn in nl.parametername: 150 | names.append(description(pn)) 151 | # Just take first name 152 | self._data['name'] = names[0] 153 | # Get description 154 | pd = description(self._parse_data.get_parameterdescription()) 155 | self._data['description'] = pd 156 | 157 | description = property(lambda self: self.data()['description']) 158 | name = property(lambda self: self.data()['name']) 159 | 160 | 161 | class DoxyClass(DoxyCompound): 162 | 163 | __module__ = "gnuradio.utils.doxyxml" 164 | 165 | kind = 'class' 166 | 167 | def _parse(self): 168 | if self._parsed: 169 | return 170 | super(DoxyClass, self)._parse() 171 | self.retrieve_data() 172 | if self._error: 173 | return 174 | self.set_descriptions(self._retrieved_data.compounddef) 175 | self.set_parameters(self._retrieved_data.compounddef) 176 | # Sectiondef.kind tells about whether private or public. 177 | # We just ignore this for now. 178 | self.process_memberdefs() 179 | 180 | brief_description = property(lambda self: self.data()['brief_description']) 181 | detailed_description = property(lambda self: self.data()['detailed_description']) 182 | params = property(lambda self: self.data()['params']) 183 | 184 | Base.mem_classes.append(DoxyClass) 185 | 186 | 187 | class DoxyFile(DoxyCompound): 188 | 189 | __module__ = "gnuradio.utils.doxyxml" 190 | 191 | kind = 'file' 192 | 193 | def _parse(self): 194 | if self._parsed: 195 | return 196 | super(DoxyFile, self)._parse() 197 | self.retrieve_data() 198 | self.set_descriptions(self._retrieved_data.compounddef) 199 | if self._error: 200 | return 201 | self.process_memberdefs() 202 | 203 | brief_description = property(lambda self: self.data()['brief_description']) 204 | detailed_description = property(lambda self: self.data()['detailed_description']) 205 | 206 | Base.mem_classes.append(DoxyFile) 207 | 208 | 209 | class DoxyNamespace(DoxyCompound): 210 | 211 | __module__ = "gnuradio.utils.doxyxml" 212 | 213 | kind = 'namespace' 214 | 215 | def _parse(self): 216 | if self._parsed: 217 | return 218 | super(DoxyNamespace, self)._parse() 219 | self.retrieve_data() 220 | self.set_descriptions(self._retrieved_data.compounddef) 221 | if self._error: 222 | return 223 | self.process_memberdefs() 224 | 225 | Base.mem_classes.append(DoxyNamespace) 226 | 227 | 228 | class DoxyGroup(DoxyCompound): 229 | 230 | __module__ = "gnuradio.utils.doxyxml" 231 | 232 | kind = 'group' 233 | 234 | def _parse(self): 235 | if self._parsed: 236 | return 237 | super(DoxyGroup, self)._parse() 238 | self.retrieve_data() 239 | if self._error: 240 | return 241 | cdef = self._retrieved_data.compounddef 242 | self._data['title'] = description(cdef.title) 243 | # Process inner groups 244 | grps = cdef.innergroup 245 | for grp in grps: 246 | converted = DoxyGroup.from_refid(grp.refid, top=self.top) 247 | self._members.append(converted) 248 | # Process inner classes 249 | klasses = cdef.innerclass 250 | for kls in klasses: 251 | converted = DoxyClass.from_refid(kls.refid, top=self.top) 252 | self._members.append(converted) 253 | # Process normal members 254 | self.process_memberdefs() 255 | 256 | title = property(lambda self: self.data()['title']) 257 | 258 | 259 | Base.mem_classes.append(DoxyGroup) 260 | 261 | 262 | class DoxyFriend(DoxyMember): 263 | 264 | __module__ = "gnuradio.utils.doxyxml" 265 | 266 | kind = 'friend' 267 | 268 | Base.mem_classes.append(DoxyFriend) 269 | 270 | 271 | class DoxyOther(Base): 272 | 273 | __module__ = "gnuradio.utils.doxyxml" 274 | 275 | kinds = set(['variable', 'struct', 'union', 'define', 'typedef', 'enum', 276 | 'dir', 'page', 'signal', 'slot', 'property']) 277 | 278 | @classmethod 279 | def can_parse(cls, obj): 280 | return obj.kind in cls.kinds 281 | 282 | Base.mem_classes.append(DoxyOther) 283 | -------------------------------------------------------------------------------- /docs/doxygen/doxyxml/generated/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Contains generated files produced by generateDS.py. 3 | 4 | These do the real work of parsing the doxygen xml files but the 5 | resultant classes are not very friendly to navigate so the rest of the 6 | doxyxml module processes them further. 7 | """ 8 | -------------------------------------------------------------------------------- /docs/doxygen/doxyxml/generated/compound.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Generated Mon Feb 9 19:08:05 2009 by generateDS.py. 5 | """ 6 | 7 | 8 | from xml.dom import minidom 9 | from xml.dom import Node 10 | 11 | import sys 12 | 13 | from . import compoundsuper as supermod 14 | from .compoundsuper import MixedContainer 15 | 16 | 17 | class DoxygenTypeSub(supermod.DoxygenType): 18 | def __init__(self, version=None, compounddef=None): 19 | supermod.DoxygenType.__init__(self, version, compounddef) 20 | 21 | def find(self, details): 22 | 23 | return self.compounddef.find(details) 24 | 25 | supermod.DoxygenType.subclass = DoxygenTypeSub 26 | # end class DoxygenTypeSub 27 | 28 | 29 | class compounddefTypeSub(supermod.compounddefType): 30 | def __init__(self, kind=None, prot=None, id=None, compoundname='', title='', basecompoundref=None, derivedcompoundref=None, includes=None, includedby=None, incdepgraph=None, invincdepgraph=None, innerdir=None, innerfile=None, innerclass=None, innernamespace=None, innerpage=None, innergroup=None, templateparamlist=None, sectiondef=None, briefdescription=None, detaileddescription=None, inheritancegraph=None, collaborationgraph=None, programlisting=None, location=None, listofallmembers=None): 31 | supermod.compounddefType.__init__(self, kind, prot, id, compoundname, title, basecompoundref, derivedcompoundref, includes, includedby, incdepgraph, invincdepgraph, innerdir, innerfile, innerclass, innernamespace, innerpage, innergroup, templateparamlist, sectiondef, briefdescription, detaileddescription, inheritancegraph, collaborationgraph, programlisting, location, listofallmembers) 32 | 33 | def find(self, details): 34 | 35 | if self.id == details.refid: 36 | return self 37 | 38 | for sectiondef in self.sectiondef: 39 | result = sectiondef.find(details) 40 | if result: 41 | return result 42 | 43 | 44 | supermod.compounddefType.subclass = compounddefTypeSub 45 | # end class compounddefTypeSub 46 | 47 | 48 | class listofallmembersTypeSub(supermod.listofallmembersType): 49 | def __init__(self, member=None): 50 | supermod.listofallmembersType.__init__(self, member) 51 | supermod.listofallmembersType.subclass = listofallmembersTypeSub 52 | # end class listofallmembersTypeSub 53 | 54 | 55 | class memberRefTypeSub(supermod.memberRefType): 56 | def __init__(self, virt=None, prot=None, refid=None, ambiguityscope=None, scope='', name=''): 57 | supermod.memberRefType.__init__(self, virt, prot, refid, ambiguityscope, scope, name) 58 | supermod.memberRefType.subclass = memberRefTypeSub 59 | # end class memberRefTypeSub 60 | 61 | 62 | class compoundRefTypeSub(supermod.compoundRefType): 63 | def __init__(self, virt=None, prot=None, refid=None, valueOf_='', mixedclass_=None, content_=None): 64 | supermod.compoundRefType.__init__(self, mixedclass_, content_) 65 | supermod.compoundRefType.subclass = compoundRefTypeSub 66 | # end class compoundRefTypeSub 67 | 68 | 69 | class reimplementTypeSub(supermod.reimplementType): 70 | def __init__(self, refid=None, valueOf_='', mixedclass_=None, content_=None): 71 | supermod.reimplementType.__init__(self, mixedclass_, content_) 72 | supermod.reimplementType.subclass = reimplementTypeSub 73 | # end class reimplementTypeSub 74 | 75 | 76 | class incTypeSub(supermod.incType): 77 | def __init__(self, local=None, refid=None, valueOf_='', mixedclass_=None, content_=None): 78 | supermod.incType.__init__(self, mixedclass_, content_) 79 | supermod.incType.subclass = incTypeSub 80 | # end class incTypeSub 81 | 82 | 83 | class refTypeSub(supermod.refType): 84 | def __init__(self, prot=None, refid=None, valueOf_='', mixedclass_=None, content_=None): 85 | supermod.refType.__init__(self, mixedclass_, content_) 86 | supermod.refType.subclass = refTypeSub 87 | # end class refTypeSub 88 | 89 | 90 | 91 | class refTextTypeSub(supermod.refTextType): 92 | def __init__(self, refid=None, kindref=None, external=None, valueOf_='', mixedclass_=None, content_=None): 93 | supermod.refTextType.__init__(self, mixedclass_, content_) 94 | 95 | supermod.refTextType.subclass = refTextTypeSub 96 | # end class refTextTypeSub 97 | 98 | class sectiondefTypeSub(supermod.sectiondefType): 99 | 100 | 101 | def __init__(self, kind=None, header='', description=None, memberdef=None): 102 | supermod.sectiondefType.__init__(self, kind, header, description, memberdef) 103 | 104 | def find(self, details): 105 | 106 | for memberdef in self.memberdef: 107 | if memberdef.id == details.refid: 108 | return memberdef 109 | 110 | return None 111 | 112 | 113 | supermod.sectiondefType.subclass = sectiondefTypeSub 114 | # end class sectiondefTypeSub 115 | 116 | 117 | class memberdefTypeSub(supermod.memberdefType): 118 | def __init__(self, initonly=None, kind=None, volatile=None, const=None, raise_=None, virt=None, readable=None, prot=None, explicit=None, new=None, final=None, writable=None, add=None, static=None, remove=None, sealed=None, mutable=None, gettable=None, inline=None, settable=None, id=None, templateparamlist=None, type_=None, definition='', argsstring='', name='', read='', write='', bitfield='', reimplements=None, reimplementedby=None, param=None, enumvalue=None, initializer=None, exceptions=None, briefdescription=None, detaileddescription=None, inbodydescription=None, location=None, references=None, referencedby=None): 119 | supermod.memberdefType.__init__(self, initonly, kind, volatile, const, raise_, virt, readable, prot, explicit, new, final, writable, add, static, remove, sealed, mutable, gettable, inline, settable, id, templateparamlist, type_, definition, argsstring, name, read, write, bitfield, reimplements, reimplementedby, param, enumvalue, initializer, exceptions, briefdescription, detaileddescription, inbodydescription, location, references, referencedby) 120 | supermod.memberdefType.subclass = memberdefTypeSub 121 | # end class memberdefTypeSub 122 | 123 | 124 | class descriptionTypeSub(supermod.descriptionType): 125 | def __init__(self, title='', para=None, sect1=None, internal=None, mixedclass_=None, content_=None): 126 | supermod.descriptionType.__init__(self, mixedclass_, content_) 127 | supermod.descriptionType.subclass = descriptionTypeSub 128 | # end class descriptionTypeSub 129 | 130 | 131 | class enumvalueTypeSub(supermod.enumvalueType): 132 | def __init__(self, prot=None, id=None, name='', initializer=None, briefdescription=None, detaileddescription=None, mixedclass_=None, content_=None): 133 | supermod.enumvalueType.__init__(self, mixedclass_, content_) 134 | supermod.enumvalueType.subclass = enumvalueTypeSub 135 | # end class enumvalueTypeSub 136 | 137 | 138 | class templateparamlistTypeSub(supermod.templateparamlistType): 139 | def __init__(self, param=None): 140 | supermod.templateparamlistType.__init__(self, param) 141 | supermod.templateparamlistType.subclass = templateparamlistTypeSub 142 | # end class templateparamlistTypeSub 143 | 144 | 145 | class paramTypeSub(supermod.paramType): 146 | def __init__(self, type_=None, declname='', defname='', array='', defval=None, briefdescription=None): 147 | supermod.paramType.__init__(self, type_, declname, defname, array, defval, briefdescription) 148 | supermod.paramType.subclass = paramTypeSub 149 | # end class paramTypeSub 150 | 151 | 152 | class linkedTextTypeSub(supermod.linkedTextType): 153 | def __init__(self, ref=None, mixedclass_=None, content_=None): 154 | supermod.linkedTextType.__init__(self, mixedclass_, content_) 155 | supermod.linkedTextType.subclass = linkedTextTypeSub 156 | # end class linkedTextTypeSub 157 | 158 | 159 | class graphTypeSub(supermod.graphType): 160 | def __init__(self, node=None): 161 | supermod.graphType.__init__(self, node) 162 | supermod.graphType.subclass = graphTypeSub 163 | # end class graphTypeSub 164 | 165 | 166 | class nodeTypeSub(supermod.nodeType): 167 | def __init__(self, id=None, label='', link=None, childnode=None): 168 | supermod.nodeType.__init__(self, id, label, link, childnode) 169 | supermod.nodeType.subclass = nodeTypeSub 170 | # end class nodeTypeSub 171 | 172 | 173 | class childnodeTypeSub(supermod.childnodeType): 174 | def __init__(self, relation=None, refid=None, edgelabel=None): 175 | supermod.childnodeType.__init__(self, relation, refid, edgelabel) 176 | supermod.childnodeType.subclass = childnodeTypeSub 177 | # end class childnodeTypeSub 178 | 179 | 180 | class linkTypeSub(supermod.linkType): 181 | def __init__(self, refid=None, external=None, valueOf_=''): 182 | supermod.linkType.__init__(self, refid, external) 183 | supermod.linkType.subclass = linkTypeSub 184 | # end class linkTypeSub 185 | 186 | 187 | class listingTypeSub(supermod.listingType): 188 | def __init__(self, codeline=None): 189 | supermod.listingType.__init__(self, codeline) 190 | supermod.listingType.subclass = listingTypeSub 191 | # end class listingTypeSub 192 | 193 | 194 | class codelineTypeSub(supermod.codelineType): 195 | def __init__(self, external=None, lineno=None, refkind=None, refid=None, highlight=None): 196 | supermod.codelineType.__init__(self, external, lineno, refkind, refid, highlight) 197 | supermod.codelineType.subclass = codelineTypeSub 198 | # end class codelineTypeSub 199 | 200 | 201 | class highlightTypeSub(supermod.highlightType): 202 | def __init__(self, class_=None, sp=None, ref=None, mixedclass_=None, content_=None): 203 | supermod.highlightType.__init__(self, mixedclass_, content_) 204 | supermod.highlightType.subclass = highlightTypeSub 205 | # end class highlightTypeSub 206 | 207 | 208 | class referenceTypeSub(supermod.referenceType): 209 | def __init__(self, endline=None, startline=None, refid=None, compoundref=None, valueOf_='', mixedclass_=None, content_=None): 210 | supermod.referenceType.__init__(self, mixedclass_, content_) 211 | supermod.referenceType.subclass = referenceTypeSub 212 | # end class referenceTypeSub 213 | 214 | 215 | class locationTypeSub(supermod.locationType): 216 | def __init__(self, bodystart=None, line=None, bodyend=None, bodyfile=None, file=None, valueOf_=''): 217 | supermod.locationType.__init__(self, bodystart, line, bodyend, bodyfile, file) 218 | supermod.locationType.subclass = locationTypeSub 219 | # end class locationTypeSub 220 | 221 | 222 | class docSect1TypeSub(supermod.docSect1Type): 223 | def __init__(self, id=None, title='', para=None, sect2=None, internal=None, mixedclass_=None, content_=None): 224 | supermod.docSect1Type.__init__(self, mixedclass_, content_) 225 | supermod.docSect1Type.subclass = docSect1TypeSub 226 | # end class docSect1TypeSub 227 | 228 | 229 | class docSect2TypeSub(supermod.docSect2Type): 230 | def __init__(self, id=None, title='', para=None, sect3=None, internal=None, mixedclass_=None, content_=None): 231 | supermod.docSect2Type.__init__(self, mixedclass_, content_) 232 | supermod.docSect2Type.subclass = docSect2TypeSub 233 | # end class docSect2TypeSub 234 | 235 | 236 | class docSect3TypeSub(supermod.docSect3Type): 237 | def __init__(self, id=None, title='', para=None, sect4=None, internal=None, mixedclass_=None, content_=None): 238 | supermod.docSect3Type.__init__(self, mixedclass_, content_) 239 | supermod.docSect3Type.subclass = docSect3TypeSub 240 | # end class docSect3TypeSub 241 | 242 | 243 | class docSect4TypeSub(supermod.docSect4Type): 244 | def __init__(self, id=None, title='', para=None, internal=None, mixedclass_=None, content_=None): 245 | supermod.docSect4Type.__init__(self, mixedclass_, content_) 246 | supermod.docSect4Type.subclass = docSect4TypeSub 247 | # end class docSect4TypeSub 248 | 249 | 250 | class docInternalTypeSub(supermod.docInternalType): 251 | def __init__(self, para=None, sect1=None, mixedclass_=None, content_=None): 252 | supermod.docInternalType.__init__(self, mixedclass_, content_) 253 | supermod.docInternalType.subclass = docInternalTypeSub 254 | # end class docInternalTypeSub 255 | 256 | 257 | class docInternalS1TypeSub(supermod.docInternalS1Type): 258 | def __init__(self, para=None, sect2=None, mixedclass_=None, content_=None): 259 | supermod.docInternalS1Type.__init__(self, mixedclass_, content_) 260 | supermod.docInternalS1Type.subclass = docInternalS1TypeSub 261 | # end class docInternalS1TypeSub 262 | 263 | 264 | class docInternalS2TypeSub(supermod.docInternalS2Type): 265 | def __init__(self, para=None, sect3=None, mixedclass_=None, content_=None): 266 | supermod.docInternalS2Type.__init__(self, mixedclass_, content_) 267 | supermod.docInternalS2Type.subclass = docInternalS2TypeSub 268 | # end class docInternalS2TypeSub 269 | 270 | 271 | class docInternalS3TypeSub(supermod.docInternalS3Type): 272 | def __init__(self, para=None, sect3=None, mixedclass_=None, content_=None): 273 | supermod.docInternalS3Type.__init__(self, mixedclass_, content_) 274 | supermod.docInternalS3Type.subclass = docInternalS3TypeSub 275 | # end class docInternalS3TypeSub 276 | 277 | 278 | class docInternalS4TypeSub(supermod.docInternalS4Type): 279 | def __init__(self, para=None, mixedclass_=None, content_=None): 280 | supermod.docInternalS4Type.__init__(self, mixedclass_, content_) 281 | supermod.docInternalS4Type.subclass = docInternalS4TypeSub 282 | # end class docInternalS4TypeSub 283 | 284 | 285 | class docURLLinkSub(supermod.docURLLink): 286 | def __init__(self, url=None, valueOf_='', mixedclass_=None, content_=None): 287 | supermod.docURLLink.__init__(self, mixedclass_, content_) 288 | supermod.docURLLink.subclass = docURLLinkSub 289 | # end class docURLLinkSub 290 | 291 | 292 | class docAnchorTypeSub(supermod.docAnchorType): 293 | def __init__(self, id=None, valueOf_='', mixedclass_=None, content_=None): 294 | supermod.docAnchorType.__init__(self, mixedclass_, content_) 295 | supermod.docAnchorType.subclass = docAnchorTypeSub 296 | # end class docAnchorTypeSub 297 | 298 | 299 | class docFormulaTypeSub(supermod.docFormulaType): 300 | def __init__(self, id=None, valueOf_='', mixedclass_=None, content_=None): 301 | supermod.docFormulaType.__init__(self, mixedclass_, content_) 302 | supermod.docFormulaType.subclass = docFormulaTypeSub 303 | # end class docFormulaTypeSub 304 | 305 | 306 | class docIndexEntryTypeSub(supermod.docIndexEntryType): 307 | def __init__(self, primaryie='', secondaryie=''): 308 | supermod.docIndexEntryType.__init__(self, primaryie, secondaryie) 309 | supermod.docIndexEntryType.subclass = docIndexEntryTypeSub 310 | # end class docIndexEntryTypeSub 311 | 312 | 313 | class docListTypeSub(supermod.docListType): 314 | def __init__(self, listitem=None): 315 | supermod.docListType.__init__(self, listitem) 316 | supermod.docListType.subclass = docListTypeSub 317 | # end class docListTypeSub 318 | 319 | 320 | class docListItemTypeSub(supermod.docListItemType): 321 | def __init__(self, para=None): 322 | supermod.docListItemType.__init__(self, para) 323 | supermod.docListItemType.subclass = docListItemTypeSub 324 | # end class docListItemTypeSub 325 | 326 | 327 | class docSimpleSectTypeSub(supermod.docSimpleSectType): 328 | def __init__(self, kind=None, title=None, para=None): 329 | supermod.docSimpleSectType.__init__(self, kind, title, para) 330 | supermod.docSimpleSectType.subclass = docSimpleSectTypeSub 331 | # end class docSimpleSectTypeSub 332 | 333 | 334 | class docVarListEntryTypeSub(supermod.docVarListEntryType): 335 | def __init__(self, term=None): 336 | supermod.docVarListEntryType.__init__(self, term) 337 | supermod.docVarListEntryType.subclass = docVarListEntryTypeSub 338 | # end class docVarListEntryTypeSub 339 | 340 | 341 | class docRefTextTypeSub(supermod.docRefTextType): 342 | def __init__(self, refid=None, kindref=None, external=None, valueOf_='', mixedclass_=None, content_=None): 343 | supermod.docRefTextType.__init__(self, mixedclass_, content_) 344 | supermod.docRefTextType.subclass = docRefTextTypeSub 345 | # end class docRefTextTypeSub 346 | 347 | 348 | class docTableTypeSub(supermod.docTableType): 349 | def __init__(self, rows=None, cols=None, row=None, caption=None): 350 | supermod.docTableType.__init__(self, rows, cols, row, caption) 351 | supermod.docTableType.subclass = docTableTypeSub 352 | # end class docTableTypeSub 353 | 354 | 355 | class docRowTypeSub(supermod.docRowType): 356 | def __init__(self, entry=None): 357 | supermod.docRowType.__init__(self, entry) 358 | supermod.docRowType.subclass = docRowTypeSub 359 | # end class docRowTypeSub 360 | 361 | 362 | class docEntryTypeSub(supermod.docEntryType): 363 | def __init__(self, thead=None, para=None): 364 | supermod.docEntryType.__init__(self, thead, para) 365 | supermod.docEntryType.subclass = docEntryTypeSub 366 | # end class docEntryTypeSub 367 | 368 | 369 | class docHeadingTypeSub(supermod.docHeadingType): 370 | def __init__(self, level=None, valueOf_='', mixedclass_=None, content_=None): 371 | supermod.docHeadingType.__init__(self, mixedclass_, content_) 372 | supermod.docHeadingType.subclass = docHeadingTypeSub 373 | # end class docHeadingTypeSub 374 | 375 | 376 | class docImageTypeSub(supermod.docImageType): 377 | def __init__(self, width=None, type_=None, name=None, height=None, valueOf_='', mixedclass_=None, content_=None): 378 | supermod.docImageType.__init__(self, mixedclass_, content_) 379 | supermod.docImageType.subclass = docImageTypeSub 380 | # end class docImageTypeSub 381 | 382 | 383 | class docDotFileTypeSub(supermod.docDotFileType): 384 | def __init__(self, name=None, valueOf_='', mixedclass_=None, content_=None): 385 | supermod.docDotFileType.__init__(self, mixedclass_, content_) 386 | supermod.docDotFileType.subclass = docDotFileTypeSub 387 | # end class docDotFileTypeSub 388 | 389 | 390 | class docTocItemTypeSub(supermod.docTocItemType): 391 | def __init__(self, id=None, valueOf_='', mixedclass_=None, content_=None): 392 | supermod.docTocItemType.__init__(self, mixedclass_, content_) 393 | supermod.docTocItemType.subclass = docTocItemTypeSub 394 | # end class docTocItemTypeSub 395 | 396 | 397 | class docTocListTypeSub(supermod.docTocListType): 398 | def __init__(self, tocitem=None): 399 | supermod.docTocListType.__init__(self, tocitem) 400 | supermod.docTocListType.subclass = docTocListTypeSub 401 | # end class docTocListTypeSub 402 | 403 | 404 | class docLanguageTypeSub(supermod.docLanguageType): 405 | def __init__(self, langid=None, para=None): 406 | supermod.docLanguageType.__init__(self, langid, para) 407 | supermod.docLanguageType.subclass = docLanguageTypeSub 408 | # end class docLanguageTypeSub 409 | 410 | 411 | class docParamListTypeSub(supermod.docParamListType): 412 | def __init__(self, kind=None, parameteritem=None): 413 | supermod.docParamListType.__init__(self, kind, parameteritem) 414 | supermod.docParamListType.subclass = docParamListTypeSub 415 | # end class docParamListTypeSub 416 | 417 | 418 | class docParamListItemSub(supermod.docParamListItem): 419 | def __init__(self, parameternamelist=None, parameterdescription=None): 420 | supermod.docParamListItem.__init__(self, parameternamelist, parameterdescription) 421 | supermod.docParamListItem.subclass = docParamListItemSub 422 | # end class docParamListItemSub 423 | 424 | 425 | class docParamNameListSub(supermod.docParamNameList): 426 | def __init__(self, parametername=None): 427 | supermod.docParamNameList.__init__(self, parametername) 428 | supermod.docParamNameList.subclass = docParamNameListSub 429 | # end class docParamNameListSub 430 | 431 | 432 | class docParamNameSub(supermod.docParamName): 433 | def __init__(self, direction=None, ref=None, mixedclass_=None, content_=None): 434 | supermod.docParamName.__init__(self, mixedclass_, content_) 435 | supermod.docParamName.subclass = docParamNameSub 436 | # end class docParamNameSub 437 | 438 | 439 | class docXRefSectTypeSub(supermod.docXRefSectType): 440 | def __init__(self, id=None, xreftitle=None, xrefdescription=None): 441 | supermod.docXRefSectType.__init__(self, id, xreftitle, xrefdescription) 442 | supermod.docXRefSectType.subclass = docXRefSectTypeSub 443 | # end class docXRefSectTypeSub 444 | 445 | 446 | class docCopyTypeSub(supermod.docCopyType): 447 | def __init__(self, link=None, para=None, sect1=None, internal=None): 448 | supermod.docCopyType.__init__(self, link, para, sect1, internal) 449 | supermod.docCopyType.subclass = docCopyTypeSub 450 | # end class docCopyTypeSub 451 | 452 | 453 | class docCharTypeSub(supermod.docCharType): 454 | def __init__(self, char=None, valueOf_=''): 455 | supermod.docCharType.__init__(self, char) 456 | supermod.docCharType.subclass = docCharTypeSub 457 | # end class docCharTypeSub 458 | 459 | class docParaTypeSub(supermod.docParaType): 460 | def __init__(self, char=None, valueOf_=''): 461 | supermod.docParaType.__init__(self, char) 462 | 463 | self.parameterlist = [] 464 | self.simplesects = [] 465 | self.content = [] 466 | 467 | def buildChildren(self, child_, nodeName_): 468 | supermod.docParaType.buildChildren(self, child_, nodeName_) 469 | 470 | if child_.nodeType == Node.TEXT_NODE: 471 | obj_ = self.mixedclass_(MixedContainer.CategoryText, 472 | MixedContainer.TypeNone, '', child_.nodeValue) 473 | self.content.append(obj_) 474 | elif child_.nodeType == Node.ELEMENT_NODE and \ 475 | nodeName_ == "ref": 476 | obj_ = supermod.docRefTextType.factory() 477 | obj_.build(child_) 478 | self.content.append(obj_) 479 | elif child_.nodeType == Node.ELEMENT_NODE and \ 480 | nodeName_ == 'parameterlist': 481 | obj_ = supermod.docParamListType.factory() 482 | obj_.build(child_) 483 | self.parameterlist.append(obj_) 484 | elif child_.nodeType == Node.ELEMENT_NODE and \ 485 | nodeName_ == 'simplesect': 486 | obj_ = supermod.docSimpleSectType.factory() 487 | obj_.build(child_) 488 | self.simplesects.append(obj_) 489 | 490 | 491 | supermod.docParaType.subclass = docParaTypeSub 492 | # end class docParaTypeSub 493 | 494 | 495 | 496 | def parse(inFilename): 497 | doc = minidom.parse(inFilename) 498 | rootNode = doc.documentElement 499 | rootObj = supermod.DoxygenType.factory() 500 | rootObj.build(rootNode) 501 | return rootObj 502 | 503 | 504 | -------------------------------------------------------------------------------- /docs/doxygen/doxyxml/generated/index.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Generated Mon Feb 9 19:08:05 2009 by generateDS.py. 5 | """ 6 | 7 | from xml.dom import minidom 8 | 9 | import os 10 | import sys 11 | from . import compound 12 | 13 | from . import indexsuper as supermod 14 | 15 | class DoxygenTypeSub(supermod.DoxygenType): 16 | def __init__(self, version=None, compound=None): 17 | supermod.DoxygenType.__init__(self, version, compound) 18 | 19 | def find_compounds_and_members(self, details): 20 | """ 21 | Returns a list of all compounds and their members which match details 22 | """ 23 | 24 | results = [] 25 | for compound in self.compound: 26 | members = compound.find_members(details) 27 | if members: 28 | results.append([compound, members]) 29 | else: 30 | if details.match(compound): 31 | results.append([compound, []]) 32 | 33 | return results 34 | 35 | supermod.DoxygenType.subclass = DoxygenTypeSub 36 | # end class DoxygenTypeSub 37 | 38 | 39 | class CompoundTypeSub(supermod.CompoundType): 40 | def __init__(self, kind=None, refid=None, name='', member=None): 41 | supermod.CompoundType.__init__(self, kind, refid, name, member) 42 | 43 | def find_members(self, details): 44 | """ 45 | Returns a list of all members which match details 46 | """ 47 | 48 | results = [] 49 | 50 | for member in self.member: 51 | if details.match(member): 52 | results.append(member) 53 | 54 | return results 55 | 56 | supermod.CompoundType.subclass = CompoundTypeSub 57 | # end class CompoundTypeSub 58 | 59 | 60 | class MemberTypeSub(supermod.MemberType): 61 | 62 | def __init__(self, kind=None, refid=None, name=''): 63 | supermod.MemberType.__init__(self, kind, refid, name) 64 | 65 | supermod.MemberType.subclass = MemberTypeSub 66 | # end class MemberTypeSub 67 | 68 | 69 | def parse(inFilename): 70 | 71 | doc = minidom.parse(inFilename) 72 | rootNode = doc.documentElement 73 | rootObj = supermod.DoxygenType.factory() 74 | rootObj.build(rootNode) 75 | 76 | return rootObj 77 | 78 | -------------------------------------------------------------------------------- /docs/doxygen/doxyxml/generated/indexsuper.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # 4 | # Generated Thu Jun 11 18:43:54 2009 by generateDS.py. 5 | # 6 | 7 | 8 | import sys 9 | 10 | from xml.dom import minidom 11 | from xml.dom import Node 12 | 13 | # 14 | # User methods 15 | # 16 | # Calls to the methods in these classes are generated by generateDS.py. 17 | # You can replace these methods by re-implementing the following class 18 | # in a module named generatedssuper.py. 19 | 20 | try: 21 | from generatedssuper import GeneratedsSuper 22 | except ImportError as exp: 23 | 24 | class GeneratedsSuper(object): 25 | def format_string(self, input_data, input_name=''): 26 | return input_data 27 | def format_integer(self, input_data, input_name=''): 28 | return '%d' % input_data 29 | def format_float(self, input_data, input_name=''): 30 | return '%f' % input_data 31 | def format_double(self, input_data, input_name=''): 32 | return '%e' % input_data 33 | def format_boolean(self, input_data, input_name=''): 34 | return '%s' % input_data 35 | 36 | 37 | # 38 | # If you have installed IPython you can uncomment and use the following. 39 | # IPython is available from http://ipython.scipy.org/. 40 | # 41 | 42 | ## from IPython.Shell import IPShellEmbed 43 | ## args = '' 44 | ## ipshell = IPShellEmbed(args, 45 | ## banner = 'Dropping into IPython', 46 | ## exit_msg = 'Leaving Interpreter, back to program.') 47 | 48 | # Then use the following line where and when you want to drop into the 49 | # IPython shell: 50 | # ipshell(' -- Entering ipshell.\nHit Ctrl-D to exit') 51 | 52 | # 53 | # Globals 54 | # 55 | 56 | ExternalEncoding = 'ascii' 57 | 58 | # 59 | # Support/utility functions. 60 | # 61 | 62 | def showIndent(outfile, level): 63 | for idx in range(level): 64 | outfile.write(' ') 65 | 66 | def quote_xml(inStr): 67 | s1 = (isinstance(inStr, str) and inStr or 68 | '%s' % inStr) 69 | s1 = s1.replace('&', '&') 70 | s1 = s1.replace('<', '<') 71 | s1 = s1.replace('>', '>') 72 | return s1 73 | 74 | def quote_attrib(inStr): 75 | s1 = (isinstance(inStr, str) and inStr or 76 | '%s' % inStr) 77 | s1 = s1.replace('&', '&') 78 | s1 = s1.replace('<', '<') 79 | s1 = s1.replace('>', '>') 80 | if '"' in s1: 81 | if "'" in s1: 82 | s1 = '"%s"' % s1.replace('"', """) 83 | else: 84 | s1 = "'%s'" % s1 85 | else: 86 | s1 = '"%s"' % s1 87 | return s1 88 | 89 | def quote_python(inStr): 90 | s1 = inStr 91 | if s1.find("'") == -1: 92 | if s1.find('\n') == -1: 93 | return "'%s'" % s1 94 | else: 95 | return "'''%s'''" % s1 96 | else: 97 | if s1.find('"') != -1: 98 | s1 = s1.replace('"', '\\"') 99 | if s1.find('\n') == -1: 100 | return '"%s"' % s1 101 | else: 102 | return '"""%s"""' % s1 103 | 104 | 105 | class MixedContainer(object): 106 | # Constants for category: 107 | CategoryNone = 0 108 | CategoryText = 1 109 | CategorySimple = 2 110 | CategoryComplex = 3 111 | # Constants for content_type: 112 | TypeNone = 0 113 | TypeText = 1 114 | TypeString = 2 115 | TypeInteger = 3 116 | TypeFloat = 4 117 | TypeDecimal = 5 118 | TypeDouble = 6 119 | TypeBoolean = 7 120 | def __init__(self, category, content_type, name, value): 121 | self.category = category 122 | self.content_type = content_type 123 | self.name = name 124 | self.value = value 125 | def getCategory(self): 126 | return self.category 127 | def getContenttype(self, content_type): 128 | return self.content_type 129 | def getValue(self): 130 | return self.value 131 | def getName(self): 132 | return self.name 133 | def export(self, outfile, level, name, namespace): 134 | if self.category == MixedContainer.CategoryText: 135 | outfile.write(self.value) 136 | elif self.category == MixedContainer.CategorySimple: 137 | self.exportSimple(outfile, level, name) 138 | else: # category == MixedContainer.CategoryComplex 139 | self.value.export(outfile, level, namespace,name) 140 | def exportSimple(self, outfile, level, name): 141 | if self.content_type == MixedContainer.TypeString: 142 | outfile.write('<%s>%s' % (self.name, self.value, self.name)) 143 | elif self.content_type == MixedContainer.TypeInteger or \ 144 | self.content_type == MixedContainer.TypeBoolean: 145 | outfile.write('<%s>%d' % (self.name, self.value, self.name)) 146 | elif self.content_type == MixedContainer.TypeFloat or \ 147 | self.content_type == MixedContainer.TypeDecimal: 148 | outfile.write('<%s>%f' % (self.name, self.value, self.name)) 149 | elif self.content_type == MixedContainer.TypeDouble: 150 | outfile.write('<%s>%g' % (self.name, self.value, self.name)) 151 | def exportLiteral(self, outfile, level, name): 152 | if self.category == MixedContainer.CategoryText: 153 | showIndent(outfile, level) 154 | outfile.write('MixedContainer(%d, %d, "%s", "%s"),\n' % \ 155 | (self.category, self.content_type, self.name, self.value)) 156 | elif self.category == MixedContainer.CategorySimple: 157 | showIndent(outfile, level) 158 | outfile.write('MixedContainer(%d, %d, "%s", "%s"),\n' % \ 159 | (self.category, self.content_type, self.name, self.value)) 160 | else: # category == MixedContainer.CategoryComplex 161 | showIndent(outfile, level) 162 | outfile.write('MixedContainer(%d, %d, "%s",\n' % \ 163 | (self.category, self.content_type, self.name,)) 164 | self.value.exportLiteral(outfile, level + 1) 165 | showIndent(outfile, level) 166 | outfile.write(')\n') 167 | 168 | 169 | class _MemberSpec(object): 170 | def __init__(self, name='', data_type='', container=0): 171 | self.name = name 172 | self.data_type = data_type 173 | self.container = container 174 | def set_name(self, name): self.name = name 175 | def get_name(self): return self.name 176 | def set_data_type(self, data_type): self.data_type = data_type 177 | def get_data_type(self): return self.data_type 178 | def set_container(self, container): self.container = container 179 | def get_container(self): return self.container 180 | 181 | 182 | # 183 | # Data representation classes. 184 | # 185 | 186 | class DoxygenType(GeneratedsSuper): 187 | subclass = None 188 | superclass = None 189 | def __init__(self, version=None, compound=None): 190 | self.version = version 191 | if compound is None: 192 | self.compound = [] 193 | else: 194 | self.compound = compound 195 | def factory(*args_, **kwargs_): 196 | if DoxygenType.subclass: 197 | return DoxygenType.subclass(*args_, **kwargs_) 198 | else: 199 | return DoxygenType(*args_, **kwargs_) 200 | factory = staticmethod(factory) 201 | def get_compound(self): return self.compound 202 | def set_compound(self, compound): self.compound = compound 203 | def add_compound(self, value): self.compound.append(value) 204 | def insert_compound(self, index, value): self.compound[index] = value 205 | def get_version(self): return self.version 206 | def set_version(self, version): self.version = version 207 | def export(self, outfile, level, namespace_='', name_='DoxygenType', namespacedef_=''): 208 | showIndent(outfile, level) 209 | outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) 210 | self.exportAttributes(outfile, level, namespace_, name_='DoxygenType') 211 | if self.hasContent_(): 212 | outfile.write('>\n') 213 | self.exportChildren(outfile, level + 1, namespace_, name_) 214 | showIndent(outfile, level) 215 | outfile.write('\n' % (namespace_, name_)) 216 | else: 217 | outfile.write(' />\n') 218 | def exportAttributes(self, outfile, level, namespace_='', name_='DoxygenType'): 219 | outfile.write(' version=%s' % (self.format_string(quote_attrib(self.version).encode(ExternalEncoding), input_name='version'), )) 220 | def exportChildren(self, outfile, level, namespace_='', name_='DoxygenType'): 221 | for compound_ in self.compound: 222 | compound_.export(outfile, level, namespace_, name_='compound') 223 | def hasContent_(self): 224 | if ( 225 | self.compound is not None 226 | ): 227 | return True 228 | else: 229 | return False 230 | def exportLiteral(self, outfile, level, name_='DoxygenType'): 231 | level += 1 232 | self.exportLiteralAttributes(outfile, level, name_) 233 | if self.hasContent_(): 234 | self.exportLiteralChildren(outfile, level, name_) 235 | def exportLiteralAttributes(self, outfile, level, name_): 236 | if self.version is not None: 237 | showIndent(outfile, level) 238 | outfile.write('version = %s,\n' % (self.version,)) 239 | def exportLiteralChildren(self, outfile, level, name_): 240 | showIndent(outfile, level) 241 | outfile.write('compound=[\n') 242 | level += 1 243 | for compound in self.compound: 244 | showIndent(outfile, level) 245 | outfile.write('model_.compound(\n') 246 | compound.exportLiteral(outfile, level, name_='compound') 247 | showIndent(outfile, level) 248 | outfile.write('),\n') 249 | level -= 1 250 | showIndent(outfile, level) 251 | outfile.write('],\n') 252 | def build(self, node_): 253 | attrs = node_.attributes 254 | self.buildAttributes(attrs) 255 | for child_ in node_.childNodes: 256 | nodeName_ = child_.nodeName.split(':')[-1] 257 | self.buildChildren(child_, nodeName_) 258 | def buildAttributes(self, attrs): 259 | if attrs.get('version'): 260 | self.version = attrs.get('version').value 261 | def buildChildren(self, child_, nodeName_): 262 | if child_.nodeType == Node.ELEMENT_NODE and \ 263 | nodeName_ == 'compound': 264 | obj_ = CompoundType.factory() 265 | obj_.build(child_) 266 | self.compound.append(obj_) 267 | # end class DoxygenType 268 | 269 | 270 | class CompoundType(GeneratedsSuper): 271 | subclass = None 272 | superclass = None 273 | def __init__(self, kind=None, refid=None, name=None, member=None): 274 | self.kind = kind 275 | self.refid = refid 276 | self.name = name 277 | if member is None: 278 | self.member = [] 279 | else: 280 | self.member = member 281 | def factory(*args_, **kwargs_): 282 | if CompoundType.subclass: 283 | return CompoundType.subclass(*args_, **kwargs_) 284 | else: 285 | return CompoundType(*args_, **kwargs_) 286 | factory = staticmethod(factory) 287 | def get_name(self): return self.name 288 | def set_name(self, name): self.name = name 289 | def get_member(self): return self.member 290 | def set_member(self, member): self.member = member 291 | def add_member(self, value): self.member.append(value) 292 | def insert_member(self, index, value): self.member[index] = value 293 | def get_kind(self): return self.kind 294 | def set_kind(self, kind): self.kind = kind 295 | def get_refid(self): return self.refid 296 | def set_refid(self, refid): self.refid = refid 297 | def export(self, outfile, level, namespace_='', name_='CompoundType', namespacedef_=''): 298 | showIndent(outfile, level) 299 | outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) 300 | self.exportAttributes(outfile, level, namespace_, name_='CompoundType') 301 | if self.hasContent_(): 302 | outfile.write('>\n') 303 | self.exportChildren(outfile, level + 1, namespace_, name_) 304 | showIndent(outfile, level) 305 | outfile.write('\n' % (namespace_, name_)) 306 | else: 307 | outfile.write(' />\n') 308 | def exportAttributes(self, outfile, level, namespace_='', name_='CompoundType'): 309 | outfile.write(' kind=%s' % (quote_attrib(self.kind), )) 310 | outfile.write(' refid=%s' % (self.format_string(quote_attrib(self.refid).encode(ExternalEncoding), input_name='refid'), )) 311 | def exportChildren(self, outfile, level, namespace_='', name_='CompoundType'): 312 | if self.name is not None: 313 | showIndent(outfile, level) 314 | outfile.write('<%sname>%s\n' % (namespace_, self.format_string(quote_xml(self.name).encode(ExternalEncoding), input_name='name'), namespace_)) 315 | for member_ in self.member: 316 | member_.export(outfile, level, namespace_, name_='member') 317 | def hasContent_(self): 318 | if ( 319 | self.name is not None or 320 | self.member is not None 321 | ): 322 | return True 323 | else: 324 | return False 325 | def exportLiteral(self, outfile, level, name_='CompoundType'): 326 | level += 1 327 | self.exportLiteralAttributes(outfile, level, name_) 328 | if self.hasContent_(): 329 | self.exportLiteralChildren(outfile, level, name_) 330 | def exportLiteralAttributes(self, outfile, level, name_): 331 | if self.kind is not None: 332 | showIndent(outfile, level) 333 | outfile.write('kind = "%s",\n' % (self.kind,)) 334 | if self.refid is not None: 335 | showIndent(outfile, level) 336 | outfile.write('refid = %s,\n' % (self.refid,)) 337 | def exportLiteralChildren(self, outfile, level, name_): 338 | showIndent(outfile, level) 339 | outfile.write('name=%s,\n' % quote_python(self.name).encode(ExternalEncoding)) 340 | showIndent(outfile, level) 341 | outfile.write('member=[\n') 342 | level += 1 343 | for member in self.member: 344 | showIndent(outfile, level) 345 | outfile.write('model_.member(\n') 346 | member.exportLiteral(outfile, level, name_='member') 347 | showIndent(outfile, level) 348 | outfile.write('),\n') 349 | level -= 1 350 | showIndent(outfile, level) 351 | outfile.write('],\n') 352 | def build(self, node_): 353 | attrs = node_.attributes 354 | self.buildAttributes(attrs) 355 | for child_ in node_.childNodes: 356 | nodeName_ = child_.nodeName.split(':')[-1] 357 | self.buildChildren(child_, nodeName_) 358 | def buildAttributes(self, attrs): 359 | if attrs.get('kind'): 360 | self.kind = attrs.get('kind').value 361 | if attrs.get('refid'): 362 | self.refid = attrs.get('refid').value 363 | def buildChildren(self, child_, nodeName_): 364 | if child_.nodeType == Node.ELEMENT_NODE and \ 365 | nodeName_ == 'name': 366 | name_ = '' 367 | for text__content_ in child_.childNodes: 368 | name_ += text__content_.nodeValue 369 | self.name = name_ 370 | elif child_.nodeType == Node.ELEMENT_NODE and \ 371 | nodeName_ == 'member': 372 | obj_ = MemberType.factory() 373 | obj_.build(child_) 374 | self.member.append(obj_) 375 | # end class CompoundType 376 | 377 | 378 | class MemberType(GeneratedsSuper): 379 | subclass = None 380 | superclass = None 381 | def __init__(self, kind=None, refid=None, name=None): 382 | self.kind = kind 383 | self.refid = refid 384 | self.name = name 385 | def factory(*args_, **kwargs_): 386 | if MemberType.subclass: 387 | return MemberType.subclass(*args_, **kwargs_) 388 | else: 389 | return MemberType(*args_, **kwargs_) 390 | factory = staticmethod(factory) 391 | def get_name(self): return self.name 392 | def set_name(self, name): self.name = name 393 | def get_kind(self): return self.kind 394 | def set_kind(self, kind): self.kind = kind 395 | def get_refid(self): return self.refid 396 | def set_refid(self, refid): self.refid = refid 397 | def export(self, outfile, level, namespace_='', name_='MemberType', namespacedef_=''): 398 | showIndent(outfile, level) 399 | outfile.write('<%s%s %s' % (namespace_, name_, namespacedef_, )) 400 | self.exportAttributes(outfile, level, namespace_, name_='MemberType') 401 | if self.hasContent_(): 402 | outfile.write('>\n') 403 | self.exportChildren(outfile, level + 1, namespace_, name_) 404 | showIndent(outfile, level) 405 | outfile.write('\n' % (namespace_, name_)) 406 | else: 407 | outfile.write(' />\n') 408 | def exportAttributes(self, outfile, level, namespace_='', name_='MemberType'): 409 | outfile.write(' kind=%s' % (quote_attrib(self.kind), )) 410 | outfile.write(' refid=%s' % (self.format_string(quote_attrib(self.refid).encode(ExternalEncoding), input_name='refid'), )) 411 | def exportChildren(self, outfile, level, namespace_='', name_='MemberType'): 412 | if self.name is not None: 413 | showIndent(outfile, level) 414 | outfile.write('<%sname>%s\n' % (namespace_, self.format_string(quote_xml(self.name).encode(ExternalEncoding), input_name='name'), namespace_)) 415 | def hasContent_(self): 416 | if ( 417 | self.name is not None 418 | ): 419 | return True 420 | else: 421 | return False 422 | def exportLiteral(self, outfile, level, name_='MemberType'): 423 | level += 1 424 | self.exportLiteralAttributes(outfile, level, name_) 425 | if self.hasContent_(): 426 | self.exportLiteralChildren(outfile, level, name_) 427 | def exportLiteralAttributes(self, outfile, level, name_): 428 | if self.kind is not None: 429 | showIndent(outfile, level) 430 | outfile.write('kind = "%s",\n' % (self.kind,)) 431 | if self.refid is not None: 432 | showIndent(outfile, level) 433 | outfile.write('refid = %s,\n' % (self.refid,)) 434 | def exportLiteralChildren(self, outfile, level, name_): 435 | showIndent(outfile, level) 436 | outfile.write('name=%s,\n' % quote_python(self.name).encode(ExternalEncoding)) 437 | def build(self, node_): 438 | attrs = node_.attributes 439 | self.buildAttributes(attrs) 440 | for child_ in node_.childNodes: 441 | nodeName_ = child_.nodeName.split(':')[-1] 442 | self.buildChildren(child_, nodeName_) 443 | def buildAttributes(self, attrs): 444 | if attrs.get('kind'): 445 | self.kind = attrs.get('kind').value 446 | if attrs.get('refid'): 447 | self.refid = attrs.get('refid').value 448 | def buildChildren(self, child_, nodeName_): 449 | if child_.nodeType == Node.ELEMENT_NODE and \ 450 | nodeName_ == 'name': 451 | name_ = '' 452 | for text__content_ in child_.childNodes: 453 | name_ += text__content_.nodeValue 454 | self.name = name_ 455 | # end class MemberType 456 | 457 | 458 | USAGE_TEXT = """ 459 | Usage: python .py [ -s ] 460 | Options: 461 | -s Use the SAX parser, not the minidom parser. 462 | """ 463 | 464 | def usage(): 465 | print(USAGE_TEXT) 466 | sys.exit(1) 467 | 468 | 469 | def parse(inFileName): 470 | doc = minidom.parse(inFileName) 471 | rootNode = doc.documentElement 472 | rootObj = DoxygenType.factory() 473 | rootObj.build(rootNode) 474 | # Enable Python to collect the space used by the DOM. 475 | doc = None 476 | sys.stdout.write('\n') 477 | rootObj.export(sys.stdout, 0, name_="doxygenindex", 478 | namespacedef_='') 479 | return rootObj 480 | 481 | 482 | def parseString(inString): 483 | doc = minidom.parseString(inString) 484 | rootNode = doc.documentElement 485 | rootObj = DoxygenType.factory() 486 | rootObj.build(rootNode) 487 | # Enable Python to collect the space used by the DOM. 488 | doc = None 489 | sys.stdout.write('\n') 490 | rootObj.export(sys.stdout, 0, name_="doxygenindex", 491 | namespacedef_='') 492 | return rootObj 493 | 494 | 495 | def parseLiteral(inFileName): 496 | doc = minidom.parse(inFileName) 497 | rootNode = doc.documentElement 498 | rootObj = DoxygenType.factory() 499 | rootObj.build(rootNode) 500 | # Enable Python to collect the space used by the DOM. 501 | doc = None 502 | sys.stdout.write('from index import *\n\n') 503 | sys.stdout.write('rootObj = doxygenindex(\n') 504 | rootObj.exportLiteral(sys.stdout, 0, name_="doxygenindex") 505 | sys.stdout.write(')\n') 506 | return rootObj 507 | 508 | 509 | def main(): 510 | args = sys.argv[1:] 511 | if len(args) == 1: 512 | parse(args[0]) 513 | else: 514 | usage() 515 | 516 | 517 | 518 | 519 | if __name__ == '__main__': 520 | main() 521 | #import pdb 522 | #pdb.run('main()') 523 | -------------------------------------------------------------------------------- /docs/doxygen/doxyxml/text.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2010 Free Software Foundation, Inc. 3 | # 4 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 5 | # This file is a part of gr-cuda 6 | # 7 | # SPDX-License-Identifier: GPL-3.0-or-later 8 | # 9 | # 10 | """ 11 | Utilities for extracting text from generated classes. 12 | """ 13 | 14 | def is_string(txt): 15 | if isinstance(txt, str): 16 | return True 17 | try: 18 | if isinstance(txt, str): 19 | return True 20 | except NameError: 21 | pass 22 | return False 23 | 24 | def description(obj): 25 | if obj is None: 26 | return None 27 | return description_bit(obj).strip() 28 | 29 | def description_bit(obj): 30 | if hasattr(obj, 'content'): 31 | contents = [description_bit(item) for item in obj.content] 32 | result = ''.join(contents) 33 | elif hasattr(obj, 'content_'): 34 | contents = [description_bit(item) for item in obj.content_] 35 | result = ''.join(contents) 36 | elif hasattr(obj, 'value'): 37 | result = description_bit(obj.value) 38 | elif is_string(obj): 39 | return obj 40 | else: 41 | raise Exception('Expecting a string or something with content, content_ or value attribute') 42 | # If this bit is a paragraph then add one some line breaks. 43 | if hasattr(obj, 'name') and obj.name == 'para': 44 | result += "\n\n" 45 | return result 46 | -------------------------------------------------------------------------------- /docs/doxygen/pydoc_macros.h: -------------------------------------------------------------------------------- 1 | #ifndef PYDOC_MACROS_H 2 | #define PYDOC_MACROS_H 3 | 4 | #define __EXPAND(x) x 5 | #define __COUNT(_1, _2, _3, _4, _5, _6, _7, COUNT, ...) COUNT 6 | #define __VA_SIZE(...) __EXPAND(__COUNT(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1)) 7 | #define __CAT1(a, b) a##b 8 | #define __CAT2(a, b) __CAT1(a, b) 9 | #define __DOC1(n1) __doc_##n1 10 | #define __DOC2(n1, n2) __doc_##n1##_##n2 11 | #define __DOC3(n1, n2, n3) __doc_##n1##_##n2##_##n3 12 | #define __DOC4(n1, n2, n3, n4) __doc_##n1##_##n2##_##n3##_##n4 13 | #define __DOC5(n1, n2, n3, n4, n5) __doc_##n1##_##n2##_##n3##_##n4##_##n5 14 | #define __DOC6(n1, n2, n3, n4, n5, n6) __doc_##n1##_##n2##_##n3##_##n4##_##n5##_##n6 15 | #define __DOC7(n1, n2, n3, n4, n5, n6, n7) \ 16 | __doc_##n1##_##n2##_##n3##_##n4##_##n5##_##n6##_##n7 17 | #define DOC(...) __EXPAND(__EXPAND(__CAT2(__DOC, __VA_SIZE(__VA_ARGS__)))(__VA_ARGS__)) 18 | 19 | #endif // PYDOC_MACROS_H -------------------------------------------------------------------------------- /docs/doxygen/update_pydoc.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2010-2012 Free Software Foundation, Inc. 3 | # 4 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 5 | # This file is a part of gnuradio 6 | # 7 | # SPDX-License-Identifier: GPL-3.0-or-later 8 | # 9 | # 10 | """ 11 | Updates the *pydoc_h files for a module 12 | Execute using: python update_pydoc.py xml_path outputfilename 13 | 14 | The file instructs Pybind11 to transfer the doxygen comments into the 15 | python docstrings. 16 | 17 | """ 18 | 19 | import os, sys, time, glob, re, json 20 | from argparse import ArgumentParser 21 | 22 | from doxyxml import DoxyIndex, DoxyClass, DoxyFriend, DoxyFunction, DoxyFile 23 | from doxyxml import DoxyOther, base 24 | 25 | def py_name(name): 26 | bits = name.split('_') 27 | return '_'.join(bits[1:]) 28 | 29 | def make_name(name): 30 | bits = name.split('_') 31 | return bits[0] + '_make_' + '_'.join(bits[1:]) 32 | 33 | 34 | class Block(object): 35 | """ 36 | Checks if doxyxml produced objects correspond to a gnuradio block. 37 | """ 38 | 39 | @classmethod 40 | def includes(cls, item): 41 | if not isinstance(item, DoxyClass): 42 | return False 43 | # Check for a parsing error. 44 | if item.error(): 45 | return False 46 | friendname = make_name(item.name()) 47 | is_a_block = item.has_member(friendname, DoxyFriend) 48 | # But now sometimes the make function isn't a friend so check again. 49 | if not is_a_block: 50 | is_a_block = di.has_member(friendname, DoxyFunction) 51 | return is_a_block 52 | 53 | class Block2(object): 54 | """ 55 | Checks if doxyxml produced objects correspond to a new style 56 | gnuradio block. 57 | """ 58 | 59 | @classmethod 60 | def includes(cls, item): 61 | if not isinstance(item, DoxyClass): 62 | return False 63 | # Check for a parsing error. 64 | if item.error(): 65 | return False 66 | is_a_block2 = item.has_member('make', DoxyFunction) and item.has_member('sptr', DoxyOther) 67 | return is_a_block2 68 | 69 | 70 | def utoascii(text): 71 | """ 72 | Convert unicode text into ascii and escape quotes and backslashes. 73 | """ 74 | if text is None: 75 | return '' 76 | out = text.encode('ascii', 'replace') 77 | # swig will require us to replace blackslash with 4 backslashes 78 | # TODO: evaluate what this should be for pybind11 79 | out = out.replace(b'\\', b'\\\\\\\\') 80 | out = out.replace(b'"', b'\\"').decode('ascii') 81 | return str(out) 82 | 83 | 84 | def combine_descriptions(obj): 85 | """ 86 | Combines the brief and detailed descriptions of an object together. 87 | """ 88 | description = [] 89 | bd = obj.brief_description.strip() 90 | dd = obj.detailed_description.strip() 91 | if bd: 92 | description.append(bd) 93 | if dd: 94 | description.append(dd) 95 | return utoascii('\n\n'.join(description)).strip() 96 | 97 | def format_params(parameteritems): 98 | output = ['Args:'] 99 | template = ' {0} : {1}' 100 | for pi in parameteritems: 101 | output.append(template.format(pi.name, pi.description)) 102 | return '\n'.join(output) 103 | 104 | entry_templ = '%feature("docstring") {name} "{docstring}"' 105 | def make_entry(obj, name=None, templ="{description}", description=None, params=[]): 106 | """ 107 | Create a docstring key/value pair, where the key is the object name. 108 | 109 | obj - a doxyxml object from which documentation will be extracted. 110 | name - the name of the C object (defaults to obj.name()) 111 | templ - an optional template for the docstring containing only one 112 | variable named 'description'. 113 | description - if this optional variable is set then it's value is 114 | used as the description instead of extracting it from obj. 115 | """ 116 | if name is None: 117 | name=obj.name() 118 | if hasattr(obj,'_parse_data') and hasattr(obj._parse_data,'definition'): 119 | name=obj._parse_data.definition.split(' ')[-1] 120 | if "operator " in name: 121 | return '' 122 | if description is None: 123 | description = combine_descriptions(obj) 124 | if params: 125 | description += '\n\n' 126 | description += utoascii(format_params(params)) 127 | docstring = templ.format(description=description) 128 | 129 | return {name: docstring} 130 | 131 | 132 | def make_class_entry(klass, description=None, ignored_methods=[], params=None): 133 | """ 134 | Create a class docstring key/value pair. 135 | """ 136 | if params is None: 137 | params = klass.params 138 | output = {} 139 | output.update(make_entry(klass, description=description, params=params)) 140 | for func in klass.in_category(DoxyFunction): 141 | if func.name() not in ignored_methods: 142 | name = klass.name() + '::' + func.name() 143 | output.update(make_entry(func, name=name)) 144 | return output 145 | 146 | 147 | def make_block_entry(di, block): 148 | """ 149 | Create class and function docstrings of a gnuradio block 150 | """ 151 | descriptions = [] 152 | # Get the documentation associated with the class. 153 | class_desc = combine_descriptions(block) 154 | if class_desc: 155 | descriptions.append(class_desc) 156 | # Get the documentation associated with the make function 157 | make_func = di.get_member(make_name(block.name()), DoxyFunction) 158 | make_func_desc = combine_descriptions(make_func) 159 | if make_func_desc: 160 | descriptions.append(make_func_desc) 161 | # Get the documentation associated with the file 162 | try: 163 | block_file = di.get_member(block.name() + ".h", DoxyFile) 164 | file_desc = combine_descriptions(block_file) 165 | if file_desc: 166 | descriptions.append(file_desc) 167 | except base.Base.NoSuchMember: 168 | # Don't worry if we can't find a matching file. 169 | pass 170 | # And join them all together to make a super duper description. 171 | super_description = "\n\n".join(descriptions) 172 | # Associate the combined description with the class and 173 | # the make function. 174 | output = {} 175 | output.update(make_class_entry(block, description=super_description)) 176 | output.update(make_entry(make_func, description=super_description, 177 | params=block.params)) 178 | return output 179 | 180 | def make_block2_entry(di, block): 181 | """ 182 | Create class and function docstrings of a new style gnuradio block 183 | """ 184 | # For new style blocks all the relevant documentation should be 185 | # associated with the 'make' method. 186 | class_description = combine_descriptions(block) 187 | make_func = block.get_member('make', DoxyFunction) 188 | make_description = combine_descriptions(make_func) 189 | description = class_description + "\n\nConstructor Specific Documentation:\n\n" + make_description 190 | # Associate the combined description with the class and 191 | # the make function. 192 | output = {} 193 | output.update(make_class_entry( 194 | block, description=description, 195 | ignored_methods=['make'], params=make_func.params)) 196 | makename = block.name() + '::make' 197 | output.update(make_entry( 198 | make_func, name=makename, description=description, 199 | params=make_func.params)) 200 | return output 201 | 202 | def get_docstrings_dict(di, custom_output=None): 203 | 204 | output = {} 205 | if custom_output: 206 | output.update(custom_output) 207 | 208 | # Create docstrings for the blocks. 209 | blocks = di.in_category(Block) 210 | blocks2 = di.in_category(Block2) 211 | 212 | make_funcs = set([]) 213 | for block in blocks: 214 | try: 215 | make_func = di.get_member(make_name(block.name()), DoxyFunction) 216 | # Don't want to risk writing to output twice. 217 | if make_func.name() not in make_funcs: 218 | make_funcs.add(make_func.name()) 219 | output.update(make_block_entry(di, block)) 220 | except block.ParsingError: 221 | sys.stderr.write('Parsing error for block {0}\n'.format(block.name())) 222 | raise 223 | 224 | for block in blocks2: 225 | try: 226 | make_func = block.get_member('make', DoxyFunction) 227 | make_func_name = block.name() +'::make' 228 | # Don't want to risk writing to output twice. 229 | if make_func_name not in make_funcs: 230 | make_funcs.add(make_func_name) 231 | output.update(make_block2_entry(di, block)) 232 | except block.ParsingError: 233 | sys.stderr.write('Parsing error for block {0}\n'.format(block.name())) 234 | raise 235 | 236 | # Create docstrings for functions 237 | # Don't include the make functions since they have already been dealt with. 238 | funcs = [f for f in di.in_category(DoxyFunction) 239 | if f.name() not in make_funcs and not f.name().startswith('std::')] 240 | for f in funcs: 241 | try: 242 | output.update(make_entry(f)) 243 | except f.ParsingError: 244 | sys.stderr.write('Parsing error for function {0}\n'.format(f.name())) 245 | 246 | # Create docstrings for classes 247 | block_names = [block.name() for block in blocks] 248 | block_names += [block.name() for block in blocks2] 249 | klasses = [k for k in di.in_category(DoxyClass) 250 | if k.name() not in block_names and not k.name().startswith('std::')] 251 | for k in klasses: 252 | try: 253 | output.update(make_class_entry(k)) 254 | except k.ParsingError: 255 | sys.stderr.write('Parsing error for class {0}\n'.format(k.name())) 256 | 257 | # Docstrings are not created for anything that is not a function or a class. 258 | # If this excludes anything important please add it here. 259 | 260 | return output 261 | 262 | def sub_docstring_in_pydoc_h(pydoc_files, docstrings_dict, output_dir, filter_str=None): 263 | if filter_str: 264 | docstrings_dict = {k: v for k, v in docstrings_dict.items() if k.startswith(filter_str)} 265 | 266 | with open(os.path.join(output_dir,'docstring_status'),'w') as status_file: 267 | 268 | for pydoc_file in pydoc_files: 269 | if filter_str: 270 | filter_str2 = "::".join((filter_str,os.path.split(pydoc_file)[-1].split('_pydoc_template.h')[0])) 271 | docstrings_dict2 = {k: v for k, v in docstrings_dict.items() if k.startswith(filter_str2)} 272 | else: 273 | docstrings_dict2 = docstrings_dict 274 | 275 | 276 | 277 | file_in = open(pydoc_file,'r').read() 278 | for key, value in docstrings_dict2.items(): 279 | file_in_tmp = file_in 280 | try: 281 | doc_key = key.split("::") 282 | # if 'gr' in doc_key: 283 | # doc_key.remove('gr') 284 | doc_key = '_'.join(doc_key) 285 | regexp = r'(__doc_{} =\sR\"doc\()[^)]*(\)doc\")'.format(doc_key) 286 | regexp = re.compile(regexp, re.MULTILINE) 287 | 288 | (file_in, nsubs) = regexp.subn(r'\1'+value+r'\2', file_in, count=1) 289 | if nsubs == 1: 290 | status_file.write("PASS: " + pydoc_file + "\n") 291 | except KeyboardInterrupt: 292 | raise KeyboardInterrupt 293 | except: # be permissive, TODO log, but just leave the docstring blank 294 | status_file.write("FAIL: " + pydoc_file + "\n") 295 | file_in = file_in_tmp 296 | 297 | output_pathname = os.path.join(output_dir, os.path.basename(pydoc_file).replace('_template.h','.h')) 298 | # FIXME: Remove this debug print 299 | print('output docstrings to {}'.format(output_pathname)) 300 | with open(output_pathname,'w') as file_out: 301 | file_out.write(file_in) 302 | 303 | def copy_docstring_templates(pydoc_files, output_dir): 304 | with open(os.path.join(output_dir,'docstring_status'),'w') as status_file: 305 | for pydoc_file in pydoc_files: 306 | file_in = open(pydoc_file,'r').read() 307 | output_pathname = os.path.join(output_dir, os.path.basename(pydoc_file).replace('_template.h','.h')) 308 | # FIXME: Remove this debug print 309 | print('copy docstrings to {}'.format(output_pathname)) 310 | with open(output_pathname,'w') as file_out: 311 | file_out.write(file_in) 312 | status_file.write("DONE") 313 | 314 | def argParse(): 315 | """Parses commandline args.""" 316 | desc='Scrape the doxygen generated xml for docstrings to insert into python bindings' 317 | parser = ArgumentParser(description=desc) 318 | 319 | parser.add_argument("function", help="Operation to perform on docstrings", choices=["scrape","sub","copy"]) 320 | 321 | parser.add_argument("--xml_path") 322 | parser.add_argument("--bindings_dir") 323 | parser.add_argument("--output_dir") 324 | parser.add_argument("--json_path") 325 | parser.add_argument("--filter", default=None) 326 | 327 | return parser.parse_args() 328 | 329 | if __name__ == "__main__": 330 | # Parse command line options and set up doxyxml. 331 | args = argParse() 332 | if args.function.lower() == 'scrape': 333 | di = DoxyIndex(args.xml_path) 334 | docstrings_dict = get_docstrings_dict(di) 335 | with open(args.json_path, 'w') as fp: 336 | json.dump(docstrings_dict, fp) 337 | elif args.function.lower() == 'sub': 338 | with open(args.json_path, 'r') as fp: 339 | docstrings_dict = json.load(fp) 340 | pydoc_files = glob.glob(os.path.join(args.bindings_dir,'*_pydoc_template.h')) 341 | sub_docstring_in_pydoc_h(pydoc_files, docstrings_dict, args.output_dir, args.filter) 342 | elif args.function.lower() == 'copy': 343 | pydoc_files = glob.glob(os.path.join(args.bindings_dir,'*_pydoc_template.h')) 344 | copy_docstring_templates(pydoc_files, args.output_dir) 345 | 346 | 347 | -------------------------------------------------------------------------------- /docs/img/flowgraph_copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnuradio/gr-cuda/d373c1b2e5f8707d8798c57be5395bdac1c73011/docs/img/flowgraph_copy.png -------------------------------------------------------------------------------- /examples/.gitignore: -------------------------------------------------------------------------------- 1 | *.py -------------------------------------------------------------------------------- /examples/README: -------------------------------------------------------------------------------- 1 | It is considered good practice to add examples in here to demonstrate the 2 | functionality of your OOT module. Python scripts, GRC flow graphs or other 3 | code can go here. 4 | 5 | -------------------------------------------------------------------------------- /examples/cuda_copy.grc: -------------------------------------------------------------------------------- 1 | options: 2 | parameters: 3 | author: Josh Morman 4 | catch_exceptions: 'False' 5 | category: '[GRC Hier Blocks]' 6 | cmake_opt: '' 7 | comment: '' 8 | copyright: '2021' 9 | description: Example of using CUDA copy block 10 | gen_cmake: 'On' 11 | gen_linking: dynamic 12 | generate_options: qt_gui 13 | hier_block_src_path: '.:' 14 | id: cuda_copy 15 | max_nouts: '0' 16 | output_language: python 17 | placement: (0,0) 18 | qt_qss_theme: '' 19 | realtime_scheduling: '' 20 | run: 'True' 21 | run_command: '{python} -u {filename}' 22 | run_options: prompt 23 | sizing_mode: fixed 24 | thread_safe_setters: '' 25 | title: CUDA Copy Example 26 | window_size: (1000,1000) 27 | states: 28 | bus_sink: false 29 | bus_source: false 30 | bus_structure: null 31 | coordinate: [8, 8] 32 | rotation: 0 33 | state: enabled 34 | 35 | blocks: 36 | - name: samp_rate 37 | id: variable 38 | parameters: 39 | comment: '' 40 | value: '32000' 41 | states: 42 | bus_sink: false 43 | bus_source: false 44 | bus_structure: null 45 | coordinate: [184, 12] 46 | rotation: 0 47 | state: enabled 48 | - name: analog_sig_source_x_0 49 | id: analog_sig_source_x 50 | parameters: 51 | affinity: '' 52 | alias: '' 53 | amp: '1' 54 | comment: '' 55 | freq: '1234' 56 | maxoutbuf: '0' 57 | minoutbuf: '0' 58 | offset: '0' 59 | phase: '0' 60 | samp_rate: samp_rate 61 | type: complex 62 | waveform: analog.GR_COS_WAVE 63 | states: 64 | bus_sink: false 65 | bus_source: false 66 | bus_structure: null 67 | coordinate: [240, 172.0] 68 | rotation: 0 69 | state: true 70 | - name: blocks_copy_0 71 | id: blocks_copy 72 | parameters: 73 | affinity: '' 74 | alias: '' 75 | comment: '' 76 | enabled: 'True' 77 | maxoutbuf: '0' 78 | minoutbuf: '0' 79 | showports: 'False' 80 | type: complex 81 | vlen: '1' 82 | states: 83 | bus_sink: false 84 | bus_source: false 85 | bus_structure: null 86 | coordinate: [920, 276.0] 87 | rotation: 0 88 | state: true 89 | - name: cuda_copy_0 90 | id: cuda_copy 91 | parameters: 92 | affinity: '' 93 | alias: '' 94 | comment: '' 95 | maxoutbuf: '0' 96 | minoutbuf: '0' 97 | type: complex 98 | vlen: '1' 99 | states: 100 | bus_sink: false 101 | bus_source: false 102 | bus_structure: null 103 | coordinate: [512, 168.0] 104 | rotation: 0 105 | state: enabled 106 | - name: cuda_copy_0_0 107 | id: cuda_copy 108 | parameters: 109 | affinity: '' 110 | alias: '' 111 | comment: '' 112 | maxoutbuf: '0' 113 | minoutbuf: '0' 114 | type: complex 115 | vlen: '1' 116 | states: 117 | bus_sink: false 118 | bus_source: false 119 | bus_structure: null 120 | coordinate: [688, 168.0] 121 | rotation: 0 122 | state: enabled 123 | - name: cuda_copy_0_0_0 124 | id: cuda_copy 125 | parameters: 126 | affinity: '' 127 | alias: '' 128 | comment: '' 129 | maxoutbuf: '0' 130 | minoutbuf: '0' 131 | type: complex 132 | vlen: '1' 133 | states: 134 | bus_sink: false 135 | bus_source: false 136 | bus_structure: null 137 | coordinate: [520, 224.0] 138 | rotation: 180 139 | state: enabled 140 | - name: cuda_copy_0_0_0_0 141 | id: cuda_copy 142 | parameters: 143 | affinity: '' 144 | alias: '' 145 | comment: '' 146 | maxoutbuf: '0' 147 | minoutbuf: '0' 148 | type: complex 149 | vlen: '1' 150 | states: 151 | bus_sink: false 152 | bus_source: false 153 | bus_structure: null 154 | coordinate: [520, 296.0] 155 | rotation: 0 156 | state: enabled 157 | - name: cuda_copy_0_0_0_0_0 158 | id: cuda_copy 159 | parameters: 160 | affinity: '' 161 | alias: '' 162 | comment: '' 163 | maxoutbuf: '0' 164 | minoutbuf: '0' 165 | type: complex 166 | vlen: '1' 167 | states: 168 | bus_sink: false 169 | bus_source: false 170 | bus_structure: null 171 | coordinate: [696, 296.0] 172 | rotation: 0 173 | state: enabled 174 | - name: cuda_copy_0_1 175 | id: cuda_copy 176 | parameters: 177 | affinity: '' 178 | alias: '' 179 | comment: '' 180 | maxoutbuf: '0' 181 | minoutbuf: '0' 182 | type: complex 183 | vlen: '1' 184 | states: 185 | bus_sink: false 186 | bus_source: false 187 | bus_structure: null 188 | coordinate: [704, 224.0] 189 | rotation: 180 190 | state: enabled 191 | - name: qtgui_time_sink_x_0 192 | id: qtgui_time_sink_x 193 | parameters: 194 | affinity: '' 195 | alias: '' 196 | alpha1: '1.0' 197 | alpha10: '1.0' 198 | alpha2: '1.0' 199 | alpha3: '1.0' 200 | alpha4: '1.0' 201 | alpha5: '1.0' 202 | alpha6: '1.0' 203 | alpha7: '1.0' 204 | alpha8: '1.0' 205 | alpha9: '1.0' 206 | autoscale: 'False' 207 | axislabels: 'True' 208 | color1: blue 209 | color10: dark blue 210 | color2: red 211 | color3: green 212 | color4: black 213 | color5: cyan 214 | color6: magenta 215 | color7: yellow 216 | color8: dark red 217 | color9: dark green 218 | comment: '' 219 | ctrlpanel: 'False' 220 | entags: 'True' 221 | grid: 'False' 222 | gui_hint: '' 223 | label1: Signal 1 224 | label10: Signal 10 225 | label2: Signal 2 226 | label3: Signal 3 227 | label4: Signal 4 228 | label5: Signal 5 229 | label6: Signal 6 230 | label7: Signal 7 231 | label8: Signal 8 232 | label9: Signal 9 233 | legend: 'True' 234 | marker1: '-1' 235 | marker10: '-1' 236 | marker2: '-1' 237 | marker3: '-1' 238 | marker4: '-1' 239 | marker5: '-1' 240 | marker6: '-1' 241 | marker7: '-1' 242 | marker8: '-1' 243 | marker9: '-1' 244 | name: '""' 245 | nconnections: '1' 246 | size: '1024' 247 | srate: samp_rate 248 | stemplot: 'False' 249 | style1: '1' 250 | style10: '1' 251 | style2: '1' 252 | style3: '1' 253 | style4: '1' 254 | style5: '1' 255 | style6: '1' 256 | style7: '1' 257 | style8: '1' 258 | style9: '1' 259 | tr_chan: '0' 260 | tr_delay: '0' 261 | tr_level: '0.0' 262 | tr_mode: qtgui.TRIG_MODE_FREE 263 | tr_slope: qtgui.TRIG_SLOPE_POS 264 | tr_tag: '""' 265 | type: complex 266 | update_time: '0.10' 267 | width1: '1' 268 | width10: '1' 269 | width2: '1' 270 | width3: '1' 271 | width4: '1' 272 | width5: '1' 273 | width6: '1' 274 | width7: '1' 275 | width8: '1' 276 | width9: '1' 277 | ylabel: Amplitude 278 | ymax: '1' 279 | ymin: '-1' 280 | yunit: '""' 281 | states: 282 | bus_sink: false 283 | bus_source: false 284 | bus_structure: null 285 | coordinate: [1112, 260.0] 286 | rotation: 0 287 | state: enabled 288 | 289 | connections: 290 | - [analog_sig_source_x_0, '0', cuda_copy_0, '0'] 291 | - [blocks_copy_0, '0', qtgui_time_sink_x_0, '0'] 292 | - [cuda_copy_0, '0', cuda_copy_0_0, '0'] 293 | - [cuda_copy_0_0, '0', cuda_copy_0_1, '0'] 294 | - [cuda_copy_0_0_0, '0', cuda_copy_0_0_0_0, '0'] 295 | - [cuda_copy_0_0_0_0, '0', cuda_copy_0_0_0_0_0, '0'] 296 | - [cuda_copy_0_0_0_0_0, '0', blocks_copy_0, '0'] 297 | - [cuda_copy_0_1, '0', cuda_copy_0_0_0, '0'] 298 | 299 | metadata: 300 | file_format: 1 301 | grc_version: 3.10.3.0 302 | -------------------------------------------------------------------------------- /examples/cuda_multiply_const.grc: -------------------------------------------------------------------------------- 1 | options: 2 | parameters: 3 | author: Josh Morman 4 | catch_exceptions: 'True' 5 | category: '[GRC Hier Blocks]' 6 | cmake_opt: '' 7 | comment: '' 8 | copyright: '2021' 9 | description: Example of using CUDA copy block 10 | gen_cmake: 'On' 11 | gen_linking: dynamic 12 | generate_options: qt_gui 13 | hier_block_src_path: '.:' 14 | id: cuda_multiply_const 15 | max_nouts: '0' 16 | output_language: python 17 | placement: (0,0) 18 | qt_qss_theme: '' 19 | realtime_scheduling: '' 20 | run: 'True' 21 | run_command: '{python} -u {filename}' 22 | run_options: prompt 23 | sizing_mode: fixed 24 | thread_safe_setters: '' 25 | title: CUDA Multiply Const Example 26 | window_size: (1000,1000) 27 | states: 28 | bus_sink: false 29 | bus_source: false 30 | bus_structure: null 31 | coordinate: [8, 8] 32 | rotation: 0 33 | state: enabled 34 | 35 | blocks: 36 | - name: k 37 | id: variable_qtgui_range 38 | parameters: 39 | comment: '' 40 | gui_hint: '' 41 | label: '' 42 | min_len: '200' 43 | orient: QtCore.Qt.Horizontal 44 | outputmsgname: value 45 | rangeType: float 46 | showports: 'False' 47 | start: '0' 48 | step: '.01' 49 | stop: '1' 50 | value: '0.5' 51 | widget: counter_slider 52 | states: 53 | bus_sink: false 54 | bus_source: false 55 | bus_structure: null 56 | coordinate: [360, 20.0] 57 | rotation: 0 58 | state: true 59 | - name: samp_rate 60 | id: variable 61 | parameters: 62 | comment: '' 63 | value: '32000' 64 | states: 65 | bus_sink: false 66 | bus_source: false 67 | bus_structure: null 68 | coordinate: [184, 12] 69 | rotation: 0 70 | state: enabled 71 | - name: analog_sig_source_x_0 72 | id: analog_sig_source_x 73 | parameters: 74 | affinity: '' 75 | alias: '' 76 | amp: '1' 77 | comment: '' 78 | freq: '1234' 79 | maxoutbuf: '0' 80 | minoutbuf: '0' 81 | offset: '0' 82 | phase: '0' 83 | samp_rate: samp_rate 84 | type: complex 85 | waveform: analog.GR_COS_WAVE 86 | states: 87 | bus_sink: false 88 | bus_source: false 89 | bus_structure: null 90 | coordinate: [264, 236.0] 91 | rotation: 0 92 | state: true 93 | - name: blocks_copy_0 94 | id: blocks_copy 95 | parameters: 96 | affinity: '' 97 | alias: '' 98 | comment: '' 99 | enabled: 'True' 100 | maxoutbuf: '0' 101 | minoutbuf: '0' 102 | showports: 'False' 103 | type: complex 104 | vlen: '1' 105 | states: 106 | bus_sink: false 107 | bus_source: false 108 | bus_structure: null 109 | coordinate: [816, 276.0] 110 | rotation: 0 111 | state: true 112 | - name: cuda_multiply_const_xx_0 113 | id: cuda_multiply_const_xx 114 | parameters: 115 | affinity: '' 116 | alias: '' 117 | comment: '' 118 | const: k 119 | maxoutbuf: '0' 120 | minoutbuf: '0' 121 | type: complex 122 | vlen: '1' 123 | states: 124 | bus_sink: false 125 | bus_source: false 126 | bus_structure: null 127 | coordinate: [520, 276.0] 128 | rotation: 0 129 | state: true 130 | - name: qtgui_time_sink_x_0 131 | id: qtgui_time_sink_x 132 | parameters: 133 | affinity: '' 134 | alias: '' 135 | alpha1: '1.0' 136 | alpha10: '1.0' 137 | alpha2: '1.0' 138 | alpha3: '1.0' 139 | alpha4: '1.0' 140 | alpha5: '1.0' 141 | alpha6: '1.0' 142 | alpha7: '1.0' 143 | alpha8: '1.0' 144 | alpha9: '1.0' 145 | autoscale: 'False' 146 | axislabels: 'True' 147 | color1: blue 148 | color10: dark blue 149 | color2: red 150 | color3: green 151 | color4: black 152 | color5: cyan 153 | color6: magenta 154 | color7: yellow 155 | color8: dark red 156 | color9: dark green 157 | comment: '' 158 | ctrlpanel: 'False' 159 | entags: 'True' 160 | grid: 'False' 161 | gui_hint: '' 162 | label1: Signal 1 163 | label10: Signal 10 164 | label2: Signal 2 165 | label3: Signal 3 166 | label4: Signal 4 167 | label5: Signal 5 168 | label6: Signal 6 169 | label7: Signal 7 170 | label8: Signal 8 171 | label9: Signal 9 172 | legend: 'True' 173 | marker1: '-1' 174 | marker10: '-1' 175 | marker2: '-1' 176 | marker3: '-1' 177 | marker4: '-1' 178 | marker5: '-1' 179 | marker6: '-1' 180 | marker7: '-1' 181 | marker8: '-1' 182 | marker9: '-1' 183 | name: '""' 184 | nconnections: '1' 185 | size: '1024' 186 | srate: samp_rate 187 | stemplot: 'False' 188 | style1: '1' 189 | style10: '1' 190 | style2: '1' 191 | style3: '1' 192 | style4: '1' 193 | style5: '1' 194 | style6: '1' 195 | style7: '1' 196 | style8: '1' 197 | style9: '1' 198 | tr_chan: '0' 199 | tr_delay: '0' 200 | tr_level: '0.0' 201 | tr_mode: qtgui.TRIG_MODE_FREE 202 | tr_slope: qtgui.TRIG_SLOPE_POS 203 | tr_tag: '""' 204 | type: complex 205 | update_time: '0.10' 206 | width1: '1' 207 | width10: '1' 208 | width2: '1' 209 | width3: '1' 210 | width4: '1' 211 | width5: '1' 212 | width6: '1' 213 | width7: '1' 214 | width8: '1' 215 | width9: '1' 216 | ylabel: Amplitude 217 | ymax: '1' 218 | ymin: '-1' 219 | yunit: '""' 220 | states: 221 | bus_sink: false 222 | bus_source: false 223 | bus_structure: null 224 | coordinate: [1032, 260.0] 225 | rotation: 0 226 | state: true 227 | 228 | connections: 229 | - [analog_sig_source_x_0, '0', cuda_multiply_const_xx_0, '0'] 230 | - [blocks_copy_0, '0', qtgui_time_sink_x_0, '0'] 231 | - [cuda_multiply_const_xx_0, '0', blocks_copy_0, '0'] 232 | 233 | metadata: 234 | file_format: 1 235 | grc_version: v3.11.0.0git-310-g66696bf2 236 | -------------------------------------------------------------------------------- /examples/load.grc: -------------------------------------------------------------------------------- 1 | options: 2 | parameters: 3 | author: Josh Morman 4 | catch_exceptions: 'True' 5 | category: '[GRC Hier Blocks]' 6 | cmake_opt: '' 7 | comment: '' 8 | copyright: '2021' 9 | description: Example of using CUDA copy block 10 | gen_cmake: 'On' 11 | gen_linking: dynamic 12 | generate_options: no_gui 13 | hier_block_src_path: '.:' 14 | id: cuda_load 15 | max_nouts: '0' 16 | output_language: python 17 | placement: (0,0) 18 | qt_qss_theme: '' 19 | realtime_scheduling: '' 20 | run: 'True' 21 | run_command: '{python} -u {filename}' 22 | run_options: run 23 | sizing_mode: fixed 24 | thread_safe_setters: '' 25 | title: CUDA Kernel Load Simulation Example 26 | window_size: (1000,1000) 27 | states: 28 | bus_sink: false 29 | bus_source: false 30 | bus_structure: null 31 | coordinate: [8, 8] 32 | rotation: 0 33 | state: enabled 34 | 35 | blocks: 36 | - name: iterations 37 | id: variable 38 | parameters: 39 | comment: '' 40 | value: '100' 41 | states: 42 | bus_sink: false 43 | bus_source: false 44 | bus_structure: null 45 | coordinate: [416, 12.0] 46 | rotation: 0 47 | state: enabled 48 | - name: num_samples 49 | id: variable 50 | parameters: 51 | comment: '' 52 | value: '10000000' 53 | states: 54 | bus_sink: false 55 | bus_source: false 56 | bus_structure: null 57 | coordinate: [200, 12.0] 58 | rotation: 0 59 | state: enabled 60 | - name: use_cb 61 | id: variable 62 | parameters: 63 | comment: "By setting this to False simulate the additional \ningress/egress incurred\ 64 | \ by not having custom buffers" 65 | value: 'False' 66 | states: 67 | bus_sink: false 68 | bus_source: false 69 | bus_structure: null 70 | coordinate: [320, 12.0] 71 | rotation: 0 72 | state: true 73 | - name: blocks_head_0 74 | id: blocks_head 75 | parameters: 76 | affinity: '' 77 | alias: '' 78 | comment: '' 79 | maxoutbuf: '0' 80 | minoutbuf: '0' 81 | num_items: num_samples 82 | type: complex 83 | vlen: '1' 84 | states: 85 | bus_sink: false 86 | bus_source: false 87 | bus_structure: null 88 | coordinate: [984, 316.0] 89 | rotation: 0 90 | state: true 91 | - name: blocks_null_sink_0 92 | id: blocks_null_sink 93 | parameters: 94 | affinity: '' 95 | alias: '' 96 | bus_structure_sink: '[[0,],]' 97 | comment: '' 98 | num_inputs: '1' 99 | type: complex 100 | vlen: '1' 101 | states: 102 | bus_sink: false 103 | bus_source: false 104 | bus_structure: null 105 | coordinate: [1184, 324.0] 106 | rotation: 0 107 | state: true 108 | - name: blocks_null_source_0 109 | id: blocks_null_source 110 | parameters: 111 | affinity: '' 112 | alias: '' 113 | bus_structure_source: '[[0,],]' 114 | comment: '' 115 | maxoutbuf: '0' 116 | minoutbuf: '0' 117 | num_outputs: '1' 118 | type: complex 119 | vlen: '1' 120 | states: 121 | bus_sink: false 122 | bus_source: false 123 | bus_structure: null 124 | coordinate: [48, 304.0] 125 | rotation: 0 126 | state: true 127 | - name: cuda_load_0 128 | id: cuda_load 129 | parameters: 130 | affinity: '' 131 | alias: '' 132 | comment: '' 133 | iterations: iterations 134 | maxoutbuf: '0' 135 | minoutbuf: '0' 136 | type: complex 137 | use_cb: use_cb 138 | vlen: '1' 139 | states: 140 | bus_sink: false 141 | bus_source: false 142 | bus_structure: null 143 | coordinate: [232, 164.0] 144 | rotation: 0 145 | state: true 146 | - name: cuda_load_0_0 147 | id: cuda_load 148 | parameters: 149 | affinity: '' 150 | alias: '' 151 | comment: '' 152 | iterations: iterations 153 | maxoutbuf: '0' 154 | minoutbuf: '0' 155 | type: complex 156 | use_cb: use_cb 157 | vlen: '1' 158 | states: 159 | bus_sink: false 160 | bus_source: false 161 | bus_structure: null 162 | coordinate: [456, 164.0] 163 | rotation: 0 164 | state: true 165 | - name: cuda_load_0_1 166 | id: cuda_load 167 | parameters: 168 | affinity: '' 169 | alias: '' 170 | comment: '' 171 | iterations: iterations 172 | maxoutbuf: '0' 173 | minoutbuf: '0' 174 | type: complex 175 | use_cb: use_cb 176 | vlen: '1' 177 | states: 178 | bus_sink: false 179 | bus_source: false 180 | bus_structure: null 181 | coordinate: [680, 164.0] 182 | rotation: 0 183 | state: true 184 | - name: cuda_load_0_3 185 | id: cuda_load 186 | parameters: 187 | affinity: '' 188 | alias: '' 189 | comment: '' 190 | iterations: iterations 191 | maxoutbuf: '0' 192 | minoutbuf: '0' 193 | type: complex 194 | use_cb: use_cb 195 | vlen: '1' 196 | states: 197 | bus_sink: false 198 | bus_source: false 199 | bus_structure: null 200 | coordinate: [904, 164.0] 201 | rotation: 0 202 | state: true 203 | - name: import_0 204 | id: import 205 | parameters: 206 | alias: '' 207 | comment: '' 208 | imports: import time 209 | states: 210 | bus_sink: false 211 | bus_source: false 212 | bus_structure: null 213 | coordinate: [672, 20.0] 214 | rotation: 0 215 | state: true 216 | - name: note_0 217 | id: note 218 | parameters: 219 | alias: '' 220 | comment: '' 221 | note: '' 222 | states: 223 | bus_sink: false 224 | bus_source: false 225 | bus_structure: null 226 | coordinate: [840, 20.0] 227 | rotation: 0 228 | state: true 229 | - name: snippet_0 230 | id: snippet 231 | parameters: 232 | alias: '' 233 | code: self.startt = time.time() 234 | comment: '' 235 | priority: '0' 236 | section: main_after_init 237 | states: 238 | bus_sink: false 239 | bus_source: false 240 | bus_structure: null 241 | coordinate: [1184, 84.0] 242 | rotation: 0 243 | state: true 244 | - name: snippet_1 245 | id: snippet 246 | parameters: 247 | alias: '' 248 | code: 'self.endt = time.time() 249 | 250 | print(f''Execution Time: {self.endt-self.startt} seconds'') 251 | 252 | 253 | # sleep so the result shows up in the terminal 254 | 255 | time.sleep(2)' 256 | comment: '' 257 | priority: '0' 258 | section: main_after_stop 259 | states: 260 | bus_sink: false 261 | bus_source: false 262 | bus_structure: null 263 | coordinate: [1192, 172.0] 264 | rotation: 0 265 | state: true 266 | 267 | connections: 268 | - [blocks_head_0, '0', blocks_null_sink_0, '0'] 269 | - [blocks_null_source_0, '0', cuda_load_0, '0'] 270 | - [cuda_load_0, '0', cuda_load_0_0, '0'] 271 | - [cuda_load_0_0, '0', cuda_load_0_1, '0'] 272 | - [cuda_load_0_1, '0', cuda_load_0_3, '0'] 273 | - [cuda_load_0_3, '0', blocks_head_0, '0'] 274 | 275 | metadata: 276 | file_format: 1 277 | grc_version: 3.10.3.0 278 | -------------------------------------------------------------------------------- /grc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Free Software Foundation, Inc. 2 | # 3 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 4 | # This file is a part of gr-cuda 5 | # 6 | # SPDX-License-Identifier: GPL-3.0-or-later 7 | # 8 | 9 | install(FILES 10 | cuda.domain.yml 11 | cuda_copy.block.yml 12 | cuda_multiply_const_xx.block.yml 13 | cuda_load.block.yml DESTINATION share/gnuradio/grc/blocks 14 | ) 15 | -------------------------------------------------------------------------------- /grc/cuda.domain.yml: -------------------------------------------------------------------------------- 1 | id: cuda 2 | label: CUDA 3 | color: "#b300ff" 4 | 5 | multiple_connections_per_input: false 6 | multiple_connections_per_output: true 7 | 8 | templates: 9 | - type: [cuda, cuda] 10 | connect: self.connect(${ make_port_sig(source) }, ${ make_port_sig(sink) }) 11 | - type: [cuda, stream] 12 | connect: self.connect(${ make_port_sig(source) }, ${ make_port_sig(sink) }) 13 | - type: [stream, cuda] 14 | connect: self.connect(${ make_port_sig(source) }, ${ make_port_sig(sink) }) 15 | 16 | -------------------------------------------------------------------------------- /grc/cuda_copy.block.yml: -------------------------------------------------------------------------------- 1 | id: cuda_copy 2 | label: Copy (CUDA) 3 | category: '[CUDA]' 4 | 5 | templates: 6 | imports: from gnuradio import cuda 7 | make: cuda.copy(${type.size}*${vlen}) 8 | parameters: 9 | - id: type 10 | label: Type 11 | dtype: enum 12 | options: [complex, float, int, short, byte] 13 | option_attributes: 14 | size: [gr.sizeof_gr_complex, gr.sizeof_float, gr.sizeof_int, gr.sizeof_short, 15 | gr.sizeof_char] 16 | hide: part 17 | - id: vlen 18 | label: Vector Length 19 | dtype: int 20 | default: '1' 21 | hide: ${ 'part' if vlen == 1 else 'none' } 22 | inputs: 23 | - label: in 24 | domain: cuda 25 | dtype: ${type} 26 | vlen: ${vlen} 27 | outputs: 28 | - label: out 29 | domain: cuda 30 | dtype: ${type} 31 | vlen: ${vlen} 32 | 33 | file_format: 1 34 | -------------------------------------------------------------------------------- /grc/cuda_load.block.yml: -------------------------------------------------------------------------------- 1 | id: cuda_load 2 | label: Load (CUDA) 3 | category: "[CUDA]" 4 | templates: 5 | imports: from gnuradio import cuda 6 | make: cuda.load(${iterations}, ${type.size}*${vlen}, ${use_cb}) 7 | parameters: 8 | - id: type 9 | label: Type 10 | dtype: enum 11 | options: [complex, float, int, short, byte] 12 | option_attributes: 13 | size: 14 | [ 15 | gr.sizeof_gr_complex, 16 | gr.sizeof_float, 17 | gr.sizeof_int, 18 | gr.sizeof_short, 19 | gr.sizeof_char, 20 | ] 21 | hide: part 22 | - id: vlen 23 | label: Vector Length 24 | dtype: int 25 | default: "1" 26 | hide: ${ 'part' if vlen == 1 else 'none' } 27 | - id: iterations 28 | label: Iterations 29 | dtype: int 30 | default: 100 31 | - id: use_cb 32 | label: Use Custom Buffers 33 | dtype: bool 34 | default: True 35 | 36 | inputs: 37 | - label: in 38 | domain: cuda 39 | dtype: ${type} 40 | vlen: ${vlen} 41 | outputs: 42 | - label: out 43 | domain: cuda 44 | dtype: ${type} 45 | vlen: ${vlen} 46 | file_format: 1 47 | -------------------------------------------------------------------------------- /grc/cuda_multiply_const_xx.block.yml: -------------------------------------------------------------------------------- 1 | id: cuda_multiply_const_xx 2 | label: Multiply Const (CUDA) 3 | flags: [ python, cpp ] 4 | category: '[CUDA]' 5 | 6 | parameters: 7 | - id: type 8 | label: IO Type 9 | dtype: enum 10 | options: [complex, float, int, short] 11 | option_attributes: 12 | fcn: [cc, ff, ii, ss] 13 | const_type: [complex, float, int, int] 14 | hide: part 15 | - id: const 16 | label: Constant 17 | dtype: ${ type.const_type } 18 | default: '0' 19 | - id: vlen 20 | label: Vector Length 21 | dtype: int 22 | default: '1' 23 | hide: ${ 'part' if vlen == 1 else 'none' } 24 | 25 | inputs: 26 | - domain: cuda 27 | dtype: ${ type } 28 | vlen: ${ vlen } 29 | 30 | outputs: 31 | - domain: cuda 32 | dtype: ${ type } 33 | vlen: ${ vlen } 34 | 35 | asserts: 36 | - ${ vlen > 0 } 37 | 38 | templates: 39 | imports: from gnuradio import cuda 40 | make: cuda.multiply_const_${type.fcn}(${const}, ${vlen}) 41 | callbacks: 42 | - set_k(${const}) 43 | 44 | cpp_templates: 45 | includes: ['#include '] 46 | declarations: 'cuda::multiply_const_${type.fcn}::sptr ${id};' 47 | make: 'this->${id} = cuda::multiply_const_${type.fcn}::make(${const}, ${vlen});' 48 | callbacks: 49 | - set_k(${const}) 50 | 51 | file_format: 1 52 | -------------------------------------------------------------------------------- /include/gnuradio/cuda/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2011,2012 Free Software Foundation, Inc. 2 | # 3 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 4 | # This file is a part of gr-cuda 5 | # 6 | # SPDX-License-Identifier: GPL-3.0-or-later 7 | # 8 | 9 | ######################################################################## 10 | # Install public header files 11 | ######################################################################## 12 | install(FILES 13 | api.h 14 | cuda_error.h 15 | cuda_buffer.h 16 | cuda_block.h 17 | copy.h 18 | multiply_const.h 19 | load.h DESTINATION include/gnuradio/cuda 20 | ) 21 | -------------------------------------------------------------------------------- /include/gnuradio/cuda/api.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 Free Software Foundation, Inc. 3 | * 4 | * This file was generated by gr_modtool, a tool from the GNU Radio framework 5 | * This file is a part of gr-cuda 6 | * 7 | * SPDX-License-Identifier: GPL-3.0-or-later 8 | * 9 | */ 10 | 11 | #ifndef INCLUDED_CUDA_API_H 12 | #define INCLUDED_CUDA_API_H 13 | 14 | #include 15 | 16 | #ifdef gnuradio_cuda_EXPORTS 17 | #define CUDA_API __GR_ATTR_EXPORT 18 | #else 19 | #define CUDA_API __GR_ATTR_IMPORT 20 | #endif 21 | 22 | #endif /* INCLUDED_CUDA_API_H */ 23 | -------------------------------------------------------------------------------- /include/gnuradio/cuda/copy.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2021 Josh Morman 4 | * 5 | * This file is part of GNU Radio 6 | * 7 | * SPDX-License-Identifier: GPL-3.0-or-later 8 | * 9 | */ 10 | 11 | #ifndef INCLUDED_CUDA_COPY_H 12 | #define INCLUDED_CUDA_COPY_H 13 | 14 | #include 15 | #include 16 | 17 | namespace gr { 18 | namespace cuda { 19 | 20 | /*! 21 | * \brief <+description of block+> 22 | * \ingroup cuda 23 | * 24 | */ 25 | class CUDA_API copy : virtual public gr::sync_block { 26 | public: 27 | typedef std::shared_ptr sptr; 28 | 29 | /*! 30 | * \brief Return a shared_ptr to a new instance of cuda::copy. 31 | * 32 | * To avoid accidental use of raw pointers, cuda::copy's 33 | * constructor is in a private implementation 34 | * class. cuda::copy::make is the public interface for 35 | * creating new instances. 36 | */ 37 | static sptr make(size_t itemsize); 38 | }; 39 | 40 | } // namespace cuda 41 | } // namespace gr 42 | 43 | #endif /* INCLUDED_CUDA_COPY_H */ 44 | -------------------------------------------------------------------------------- /include/gnuradio/cuda/cuda_block.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2021 Josh Morman 4 | * 5 | * This file is part of GNU Radio 6 | * 7 | * SPDX-License-Identifier: GPL-3.0-or-later 8 | * 9 | */ 10 | 11 | #ifndef _INCLUDED_CUDA_BLOCK_H 12 | #define _INCLUDED_CUDA_BLOCK_H 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | namespace gr { 19 | 20 | class cuda_block 21 | { 22 | protected: 23 | cudaStream_t d_stream; 24 | int d_min_grid_size; 25 | int d_block_size; 26 | 27 | public: 28 | cuda_block() { check_cuda_errors(cudaStreamCreate(&d_stream)); }; 29 | }; 30 | 31 | } // namespace gr 32 | #endif -------------------------------------------------------------------------------- /include/gnuradio/cuda/cuda_buffer.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2021 BlackLynx, Inc. 4 | * 5 | * This file is part of GNU Radio 6 | * 7 | * SPDX-License-Identifier: GPL-3.0-or-later 8 | * 9 | */ 10 | 11 | #ifndef INCLUDED_GR_CUDA_H 12 | #define INCLUDED_GR_CUDA_H 13 | 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | namespace gr { 21 | 22 | /*! 23 | * \brief Subclass of buffer_single_mapped for supporting blocks using NVidia's 24 | * CUDA runtime. 25 | * 26 | * This buffer_single_mapped subclass is designed to provide easy buffer support 27 | * for blocks using NVidia's CUDA runtime. The class acts as a wrapper for two 28 | * underlying buffers, a host buffer allocated using the cudaMallocHost() 29 | * function and a device buffer allocated using the cudaMalloc() function. 30 | * The logic contained within this class manages both buffers and the movement 31 | * of data between the two depending on the buffer's assigned context. 32 | * 33 | */ 34 | class GR_RUNTIME_API cuda_buffer : public buffer_single_mapped 35 | { 36 | public: 37 | mem_func_t f_cuda_memcpy; 38 | mem_func_t f_cuda_memmove; 39 | void* cuda_memcpy(void* dest, const void* src, std::size_t count); 40 | void* cuda_memmove(void* dest, const void* src, std::size_t count); 41 | 42 | static buffer_type type; 43 | 44 | virtual ~cuda_buffer(); 45 | 46 | /*! 47 | * \brief Handle post-general_work() cleanup and data transfer 48 | * 49 | * Called directly after call to general_work() completes and 50 | * is used for data transfer (and perhaps other administrative 51 | * activities) 52 | * 53 | * \param nitems is the number of items produced by the general_work() function. 54 | */ 55 | virtual void post_work(int nitems); 56 | 57 | /*! 58 | * \brief Do actual buffer allocation. Inherited from buffer_single_mapped. 59 | */ 60 | bool do_allocate_buffer(size_t final_nitems, size_t sizeof_item); 61 | 62 | /*! 63 | * \brief Return a pointer to the write buffer depending on the context 64 | */ 65 | virtual void* write_pointer(); 66 | 67 | /*! 68 | * \brief return pointer to read buffer depending on the context 69 | * 70 | * The return value points to at least items_available() items. 71 | */ 72 | virtual const void* _read_pointer(unsigned int read_index); 73 | 74 | /*! 75 | * \brief Callback function that the scheduler will call when it determines 76 | * that the input is blocked. Override this function if needed. 77 | */ 78 | bool input_blocked_callback(int items_required, int items_avail, unsigned read_index); 79 | 80 | /*! 81 | * \brief Callback function that the scheduler will call when it determines 82 | * that the output is blocked 83 | */ 84 | bool output_blocked_callback(int output_multiple, bool force); 85 | 86 | /*! 87 | * \brief Creates a new cuda object 88 | * 89 | * \param nitems 90 | * \param sizeof_item 91 | * \param downstream_lcm_nitems 92 | * \param link 93 | * \param buf_owner 94 | * 95 | * \return pointer to buffer base class 96 | */ 97 | static buffer_sptr make_buffer(int nitems, 98 | size_t sizeof_item, 99 | uint64_t downstream_lcm_nitems, 100 | uint32_t downstream_max_out_mult, 101 | block_sptr link, 102 | block_sptr buf_owner); 103 | 104 | private: 105 | cudaStream_t d_stream; 106 | char* d_cuda_buf; // CUDA buffer 107 | 108 | /*! 109 | * \brief constructor is private. Use gr_make_buffer to create instances. 110 | * 111 | * Allocate a buffer that holds at least \p nitems of size \p sizeof_item. 112 | * 113 | * \param nitems is the minimum number of items the buffer will hold. 114 | * \param sizeof_item is the size of an item in bytes. 115 | * \param downstream_lcm_nitems is the least common multiple of the items to 116 | * read by downstream blocks 117 | * \param downstream_max_out_mult is the maximum output multiple of all 118 | * downstream blocks 119 | * \param link is the block that writes to this buffer. 120 | * \param buf_owner if the block that owns the buffer which may or may not 121 | * be the same as the block that writes to this buffer 122 | * 123 | * The total size of the buffer will be rounded up to a system 124 | * dependent boundary. This is typically the system page size, but 125 | * under MS windows is 64KB. 126 | */ 127 | cuda_buffer(int nitems, 128 | size_t sizeof_item, 129 | uint64_t downstream_lcm_nitems, 130 | uint32_t downstream_max_out_mult, 131 | block_sptr link, 132 | block_sptr buf_owner); 133 | }; 134 | 135 | } /* namespace gr */ 136 | 137 | #endif /* INCLUDED_GR_CUDA_H */ 138 | -------------------------------------------------------------------------------- /include/gnuradio/cuda/cuda_error.h: -------------------------------------------------------------------------------- 1 | #ifndef _INCLUDED_GR_CUDA_ERROR 2 | #define _INCLUDED_GR_CUDA_ERROR 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | void check_cuda_errors(cudaError_t rc); 9 | 10 | #endif -------------------------------------------------------------------------------- /include/gnuradio/cuda/load.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2022 Josh Morman. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | #ifndef INCLUDED_CUDA_LOAD_H 9 | #define INCLUDED_CUDA_LOAD_H 10 | 11 | #include 12 | #include 13 | 14 | namespace gr { 15 | namespace cuda { 16 | 17 | /*! 18 | * \brief <+description of block+> 19 | * \ingroup cuda 20 | * 21 | */ 22 | class CUDA_API load : virtual public gr::sync_block 23 | { 24 | public: 25 | typedef std::shared_ptr sptr; 26 | 27 | /*! 28 | * \brief Load block for testing CUDA workflows 29 | * 30 | * The load block provides a mechanism for loading down 31 | * the cuda processing with a for loop. This is useful 32 | * for hypothetical profiling and seeing gains in data 33 | * transfers using the custom buffers 34 | */ 35 | static sptr make(size_t iterations, size_t itemsize, bool use_cb = true); 36 | }; 37 | 38 | } // namespace cuda 39 | } // namespace gr 40 | 41 | #endif /* INCLUDED_CUDA_LOAD_H */ 42 | -------------------------------------------------------------------------------- /include/gnuradio/cuda/multiply_const.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2021 Josh Morman. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | #ifndef INCLUDED_CUDA_MULTIPLY_CONST_H 9 | #define INCLUDED_CUDA_MULTIPLY_CONST_H 10 | 11 | #include 12 | #include 13 | 14 | namespace gr { 15 | namespace cuda { 16 | 17 | /*! 18 | * \brief output = input * constant 19 | * \ingroup math_operators_blk 20 | */ 21 | template 22 | class CUDA_API multiply_const : virtual public sync_block 23 | { 24 | 25 | public: 26 | // gr::blocks::multiply_const::sptr 27 | typedef std::shared_ptr> sptr; 28 | 29 | /*! 30 | * \brief Create an instance of multiply_const 31 | * \param k multiplicative constant 32 | * \param vlen number of items in vector 33 | */ 34 | static sptr make(T k, size_t vlen = 1); 35 | 36 | /*! 37 | * \brief Return multiplicative constant 38 | */ 39 | virtual T k() const = 0; 40 | 41 | /*! 42 | * \brief Set multiplicative constant 43 | */ 44 | virtual void set_k(T k) = 0; 45 | }; 46 | 47 | typedef multiply_const multiply_const_ss; 48 | typedef multiply_const multiply_const_ii; 49 | typedef multiply_const multiply_const_ff; 50 | typedef multiply_const multiply_const_cc; 51 | 52 | } // namespace cuda 53 | } // namespace gr 54 | 55 | #endif /* INCLUDED_CUDA_MULTIPLY_CONST_H */ 56 | -------------------------------------------------------------------------------- /lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2011,2012,2016,2018,2019 Free Software Foundation, Inc. 2 | # 3 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 4 | # This file is a part of gr-cuda 5 | # 6 | # SPDX-License-Identifier: GPL-3.0-or-later 7 | # 8 | 9 | ######################################################################## 10 | # Setup library 11 | ######################################################################## 12 | include(GrPlatform) #define LIB_SUFFIX 13 | find_package(CUDA) 14 | 15 | ############################################################################### 16 | # CUDA Dependency is required 17 | ############################################################################### 18 | add_library(gnuradio-cuda-cu STATIC 19 | cuda_error.cc 20 | multiply_const.cu 21 | load.cu 22 | ) 23 | set_target_properties(gnuradio-cuda-cu PROPERTIES 24 | POSITION_INDEPENDENT_CODE ON 25 | CUDA_VISIBILITY_PRESET "hidden" 26 | CUDA_SEPARABLE_COMPILATION ON 27 | ) 28 | target_include_directories(gnuradio-cuda-cu 29 | PUBLIC $ 30 | PUBLIC $ 31 | ${CUDA_INCLUDE_DIRS} 32 | ) 33 | 34 | list(APPEND cuda_sources 35 | cuda_buffer.cc 36 | copy_impl.cc 37 | multiply_const_impl.cc 38 | load_impl.cc 39 | ) 40 | 41 | set(cuda_sources "${cuda_sources}" PARENT_SCOPE) 42 | if(NOT cuda_sources) 43 | MESSAGE(STATUS "No C++ sources... skipping lib/") 44 | return() 45 | endif(NOT cuda_sources) 46 | 47 | add_library(gnuradio-cuda SHARED ${cuda_sources}) 48 | target_link_libraries(gnuradio-cuda PUBLIC 49 | gnuradio::gnuradio-runtime 50 | ${CUDA_CUDART_LIBRARY} 51 | ) 52 | target_link_libraries(gnuradio-cuda PRIVATE gnuradio-cuda-cu) 53 | 54 | target_include_directories(gnuradio-cuda 55 | PUBLIC $ 56 | PUBLIC $ 57 | ${CUDA_INCLUDE_DIRS} 58 | ) 59 | set_target_properties(gnuradio-cuda PROPERTIES DEFINE_SYMBOL "gnuradio_cuda_EXPORTS") 60 | 61 | if(APPLE) 62 | set_target_properties(gnuradio-cuda PROPERTIES 63 | INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib" 64 | ) 65 | endif(APPLE) 66 | 67 | # Make a fat binary for supported architectures 68 | if(${CMAKE_VERSION} VERSION_LESS "3.18") 69 | # Compile for supported archs; CMake workaround, see: https://stackoverflow.com/a/54505975/73878 70 | target_compile_options(gnuradio-cuda-cu PRIVATE "$<$:SHELL:-gencode arch=compute_60,code=sm_60>") 71 | target_compile_options(gnuradio-cuda-cu PRIVATE "$<$:SHELL:-gencode arch=compute_61,code=sm_61>") 72 | target_compile_options(gnuradio-cuda-cu PRIVATE "$<$:SHELL:-gencode arch=compute_62,code=sm_62>") 73 | target_compile_options(gnuradio-cuda-cu PRIVATE "$<$:SHELL:-gencode arch=compute_70,code=sm_70>") 74 | target_compile_options(gnuradio-cuda-cu PRIVATE "$<$:SHELL:-gencode arch=compute_72,code=sm_72>") 75 | target_compile_options(gnuradio-cuda-cu PRIVATE "$<$:SHELL:-gencode arch=compute_75,code=sm_75>") 76 | # target_compile_options(gnuradio-myoot-cu PRIVATE "$<$:SHELL:-gencode arch=compute_80,code=sm_80>") 77 | # target_compile_options(gnuradio-myoot-cu PRIVATE "$<$:SHELL:-gencode arch=compute_86,code=sm_86>") 78 | else() 79 | set_target_properties(gnuradio-cuda-cu PROPERTIES CUDA_ARCHITECTURES "60;61;62;70;72;75") 80 | set_target_properties(gnuradio-cuda PROPERTIES CUDA_ARCHITECTURES "60;61;62;70;72;75") 81 | endif() 82 | 83 | ######################################################################## 84 | # Install built library files 85 | ######################################################################## 86 | include(GrMiscUtils) 87 | GR_LIBRARY_FOO(gnuradio-cuda) 88 | 89 | ######################################################################## 90 | # Print summary 91 | ######################################################################## 92 | message(STATUS "Using install prefix: ${CMAKE_INSTALL_PREFIX}") 93 | message(STATUS "Building for version: ${VERSION} / ${LIBVER}") 94 | 95 | ######################################################################## 96 | # Build and register unit test 97 | ######################################################################## 98 | include(GrTest) 99 | 100 | # If your unit tests require special include paths, add them here 101 | #include_directories() 102 | # List all files that contain Boost.UTF unit tests here 103 | list(APPEND test_cuda_sources 104 | ) 105 | # Anything we need to link to for the unit tests go here 106 | list(APPEND GR_TEST_TARGET_DEPS gnuradio-cuda) 107 | 108 | if(NOT test_cuda_sources) 109 | MESSAGE(STATUS "No C++ unit tests... skipping") 110 | return() 111 | endif(NOT test_cuda_sources) 112 | 113 | foreach(qa_file ${test_cuda_sources}) 114 | GR_ADD_CPP_TEST("cuda_${qa_file}" 115 | ${CMAKE_CURRENT_SOURCE_DIR}/${qa_file} 116 | ) 117 | endforeach(qa_file) 118 | -------------------------------------------------------------------------------- /lib/copy_impl.cc: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2004,2009,2010,2013 Free Software Foundation, Inc. 4 | * Copyright 2021 Josh Morman 5 | * 6 | * This file is part of GNU Radio 7 | * 8 | * SPDX-License-Identifier: GPL-3.0-or-later 9 | * 10 | */ 11 | 12 | #include "copy_impl.h" 13 | #include 14 | #include 15 | 16 | namespace gr { 17 | namespace cuda { 18 | 19 | copy::sptr copy::make(size_t itemsize) 20 | { 21 | return gnuradio::make_block_sptr(itemsize); 22 | } 23 | 24 | /* 25 | * The private constructor 26 | */ 27 | copy_impl::copy_impl(size_t itemsize) 28 | : gr::sync_block("copy", 29 | gr::io_signature::make(1, 1, itemsize, cuda_buffer::type), 30 | gr::io_signature::make(1, 1, itemsize, cuda_buffer::type)), 31 | d_itemsize(itemsize) 32 | { 33 | } 34 | 35 | /* 36 | * Our virtual destructor. 37 | */ 38 | copy_impl::~copy_impl() {} 39 | 40 | int copy_impl::work(int noutput_items, 41 | gr_vector_const_void_star& input_items, 42 | gr_vector_void_star& output_items) 43 | { 44 | 45 | auto in = static_cast(input_items[0]); 46 | auto out = static_cast(output_items[0]); 47 | 48 | cudaMemcpy(out, in, noutput_items * d_itemsize, cudaMemcpyDeviceToDevice); 49 | 50 | // Tell runtime system how many output items we produced. 51 | return noutput_items; 52 | } 53 | 54 | } /* namespace cuda */ 55 | } /* namespace gr */ 56 | -------------------------------------------------------------------------------- /lib/copy_impl.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2004,2009,2010,2013 Free Software Foundation, Inc. 4 | * Copyright 2021 Josh Morman 5 | * 6 | * This file is part of GNU Radio 7 | * 8 | * SPDX-License-Identifier: GPL-3.0-or-later 9 | * 10 | */ 11 | 12 | #ifndef INCLUDED_CUDA_COPY_IMPL_H 13 | #define INCLUDED_CUDA_COPY_IMPL_H 14 | 15 | #include 16 | 17 | namespace gr { 18 | namespace cuda { 19 | 20 | class copy_impl : public copy { 21 | private: 22 | size_t d_itemsize; 23 | 24 | public: 25 | copy_impl(size_t itemsize); 26 | ~copy_impl(); 27 | 28 | // Where all the action really happens 29 | int work(int noutput_items, gr_vector_const_void_star &input_items, 30 | gr_vector_void_star &output_items); 31 | }; 32 | 33 | } // namespace cuda 34 | } // namespace gr 35 | 36 | #endif /* INCLUDED_CUDA_COPY_IMPL_H */ 37 | -------------------------------------------------------------------------------- /lib/cuda_buffer.cc: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2004,2009,2010,2013 Free Software Foundation, Inc. 4 | * Copyright 2021 BlackLynx, Inc. 5 | * 6 | * This file is part of GNU Radio 7 | * 8 | * SPDX-License-Identifier: GPL-3.0-or-later 9 | * 10 | */ 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #define STREAM_COPY 1 // enabled by default 20 | 21 | namespace gr { 22 | 23 | buffer_type cuda_buffer::type(buftype{}); 24 | 25 | void* cuda_buffer::cuda_memcpy(void* dest, const void* src, std::size_t count) 26 | { 27 | cudaError_t rc = cudaSuccess; 28 | #if STREAM_COPY 29 | rc = cudaMemcpyAsync(dest, src, count, cudaMemcpyDeviceToDevice, d_stream); 30 | cudaStreamSynchronize(d_stream); 31 | #else 32 | rc = cudaMemcpy(dest, src, count, cudaMemcpyDeviceToDevice); 33 | #endif 34 | if (rc) { 35 | std::ostringstream msg; 36 | msg << "Error performing cudaMemcpy: " << cudaGetErrorName(rc) << " -- " 37 | << cudaGetErrorString(rc); 38 | throw std::runtime_error(msg.str()); 39 | } 40 | 41 | return dest; 42 | } 43 | 44 | void* cuda_buffer::cuda_memmove(void* dest, const void* src, std::size_t count) 45 | { 46 | // Would a kernel that checks for overlap and then copies front-to-back or 47 | // back-to-front be faster than using cudaMemcpy with a temp buffer? 48 | 49 | // Allocate temp buffer 50 | void* tempBuffer = nullptr; 51 | cudaError_t rc = cudaSuccess; 52 | rc = cudaMalloc((void**)&tempBuffer, count); 53 | if (rc) { 54 | std::ostringstream msg; 55 | msg << "Error allocating device buffer: " << cudaGetErrorName(rc) << " -- " 56 | << cudaGetErrorString(rc); 57 | throw std::runtime_error(msg.str()); 58 | } 59 | 60 | // First copy data from source to temp buffer 61 | #if STREAM_COPY 62 | rc = cudaMemcpyAsync(tempBuffer, src, count, cudaMemcpyDeviceToDevice, d_stream); 63 | #else 64 | rc = cudaMemcpy(tempBuffer, src, count, cudaMemcpyDeviceToDevice); 65 | #endif 66 | 67 | if (rc) { 68 | std::ostringstream msg; 69 | msg << "Error performing cudaMemcpy: " << cudaGetErrorName(rc) << " -- " 70 | << cudaGetErrorString(rc); 71 | throw std::runtime_error(msg.str()); 72 | } 73 | 74 | // Then copy data from temp buffer to destination to avoid overlap 75 | #if STREAM_COPY 76 | rc = cudaMemcpyAsync(dest, tempBuffer, count, cudaMemcpyDeviceToDevice, d_stream); 77 | #else 78 | rc = cudaMemcpy(dest, tempBuffer, count, cudaMemcpyDeviceToDevice); 79 | #endif 80 | 81 | if (rc) { 82 | std::ostringstream msg; 83 | msg << "Error performing cudaMemcpy: " << cudaGetErrorName(rc) << " -- " 84 | << cudaGetErrorString(rc); 85 | throw std::runtime_error(msg.str()); 86 | } 87 | #if STREAM_COPY 88 | cudaStreamSynchronize(d_stream); 89 | #endif 90 | 91 | cudaFree(tempBuffer); 92 | 93 | return dest; 94 | } 95 | 96 | cuda_buffer::cuda_buffer(int nitems, 97 | size_t sizeof_item, 98 | uint64_t downstream_lcm_nitems, 99 | uint32_t downstream_max_out_mult, 100 | block_sptr link, 101 | block_sptr buf_owner) 102 | : buffer_single_mapped(nitems, sizeof_item, downstream_lcm_nitems, 103 | downstream_max_out_mult, link, buf_owner), 104 | d_cuda_buf(nullptr) 105 | { 106 | gr::configure_default_loggers(d_logger, d_debug_logger, "cuda"); 107 | if (!allocate_buffer(nitems)) 108 | throw std::bad_alloc(); 109 | 110 | f_cuda_memcpy = [this](void* dest, const void* src, std::size_t count){ return this->cuda_memcpy(dest, src, count); }; 111 | f_cuda_memmove = [this](void* dest, const void* src, std::size_t count){ return this->cuda_memmove(dest, src, count); }; 112 | cudaStreamCreate(&d_stream); 113 | } 114 | 115 | cuda_buffer::~cuda_buffer() 116 | { 117 | // Free host buffer 118 | if (d_base != nullptr) { 119 | cudaFreeHost(d_base); 120 | d_base = nullptr; 121 | } 122 | 123 | // Free device buffer 124 | if (d_cuda_buf != nullptr) { 125 | cudaFree(d_cuda_buf); 126 | d_cuda_buf = nullptr; 127 | } 128 | } 129 | 130 | void cuda_buffer::post_work(int nitems) 131 | { 132 | #ifdef BUFFER_DEBUG 133 | std::ostringstream msg; 134 | msg << "[" << this << "] " 135 | << "cuda [" << d_transfer_type << "] -- post_work: " << nitems; 136 | GR_LOG_DEBUG(d_logger, msg.str()); 137 | #endif 138 | 139 | if (nitems <= 0) { 140 | return; 141 | } 142 | 143 | cudaError_t rc = cudaSuccess; 144 | 145 | // NOTE: when this function is called the write pointer has not yet been 146 | // advanced so it can be used directly as the source ptr 147 | switch (d_transfer_type) { 148 | case transfer_type::HOST_TO_DEVICE: { 149 | // Copy data from host buffer to device buffer 150 | void* dest_ptr = &d_cuda_buf[d_write_index * d_sizeof_item]; 151 | #if STREAM_COPY 152 | rc = cudaMemcpyAsync( 153 | dest_ptr, write_pointer(), nitems * d_sizeof_item, cudaMemcpyHostToDevice, d_stream); 154 | cudaStreamSynchronize(d_stream); 155 | #else 156 | rc = cudaMemcpy( 157 | dest_ptr, write_pointer(), nitems * d_sizeof_item, cudaMemcpyHostToDevice); 158 | #endif 159 | if (rc) { 160 | std::ostringstream msg; 161 | msg << "Error performing cudaMemcpy: " << cudaGetErrorName(rc) << " -- " 162 | << cudaGetErrorString(rc); 163 | GR_LOG_ERROR(d_logger, msg.str()); 164 | throw std::runtime_error(msg.str()); 165 | } 166 | 167 | } break; 168 | 169 | case transfer_type::DEVICE_TO_HOST: { 170 | // Copy data from device buffer to host buffer 171 | void* dest_ptr = &d_base[d_write_index * d_sizeof_item]; 172 | #if STREAM_COPY 173 | rc = cudaMemcpyAsync( 174 | dest_ptr, write_pointer(), nitems * d_sizeof_item, cudaMemcpyDeviceToHost, d_stream); 175 | cudaStreamSynchronize(d_stream); 176 | #else 177 | rc = cudaMemcpy( 178 | dest_ptr, write_pointer(), nitems * d_sizeof_item, cudaMemcpyDeviceToHost); 179 | #endif 180 | if (rc) { 181 | std::ostringstream msg; 182 | msg << "Error performing cudaMemcpy: " << cudaGetErrorName(rc) << " -- " 183 | << cudaGetErrorString(rc); 184 | GR_LOG_ERROR(d_logger, msg.str()); 185 | throw std::runtime_error(msg.str()); 186 | } 187 | 188 | } break; 189 | 190 | case transfer_type::DEVICE_TO_DEVICE: 191 | // No op FTW! 192 | break; 193 | 194 | default: 195 | std::ostringstream msg; 196 | msg << "Unexpected context for cuda: " << d_transfer_type; 197 | GR_LOG_ERROR(d_logger, msg.str()); 198 | throw std::runtime_error(msg.str()); 199 | } 200 | 201 | return; 202 | } 203 | 204 | bool cuda_buffer::do_allocate_buffer(size_t final_nitems, size_t sizeof_item) 205 | { 206 | #ifdef BUFFER_DEBUG 207 | { 208 | std::ostringstream msg; 209 | msg << "[" << this << "] " 210 | << "cuda constructor -- nitems: " << final_nitems; 211 | GR_LOG_DEBUG(d_logger, msg.str()); 212 | } 213 | #endif 214 | 215 | // This is the pinned host buffer 216 | // Can a CUDA buffer even use std::unique_ptr ? 217 | // d_buffer.reset(new char[final_nitems * sizeof_item]); 218 | cudaError_t rc = cudaSuccess; 219 | rc = cudaMallocHost((void**)&d_base, final_nitems * sizeof_item); 220 | if (rc) { 221 | std::ostringstream msg; 222 | msg << "Error allocating pinned host buffer: " << cudaGetErrorName(rc) << " -- " 223 | << cudaGetErrorString(rc); 224 | GR_LOG_ERROR(d_logger, msg.str()); 225 | throw std::runtime_error(msg.str()); 226 | } 227 | 228 | // This is the CUDA device buffer 229 | rc = cudaMalloc((void**)&d_cuda_buf, final_nitems * sizeof_item); 230 | if (rc) { 231 | std::ostringstream msg; 232 | msg << "Error allocating device buffer: " << cudaGetErrorName(rc) << " -- " 233 | << cudaGetErrorString(rc); 234 | GR_LOG_ERROR(d_logger, msg.str()); 235 | throw std::runtime_error(msg.str()); 236 | } 237 | 238 | return true; 239 | } 240 | 241 | void* cuda_buffer::write_pointer() 242 | { 243 | void* ptr = nullptr; 244 | switch (d_transfer_type) { 245 | case transfer_type::HOST_TO_DEVICE: 246 | // Write into host buffer 247 | ptr = &d_base[d_write_index * d_sizeof_item]; 248 | break; 249 | 250 | case transfer_type::DEVICE_TO_HOST: 251 | case transfer_type::DEVICE_TO_DEVICE: 252 | // Write into CUDA device buffer 253 | ptr = &d_cuda_buf[d_write_index * d_sizeof_item]; 254 | break; 255 | 256 | default: 257 | std::ostringstream msg; 258 | msg << "Unexpected context for cuda: " << d_transfer_type; 259 | GR_LOG_ERROR(d_logger, msg.str()); 260 | throw std::runtime_error(msg.str()); 261 | } 262 | 263 | return ptr; 264 | } 265 | 266 | const void* cuda_buffer::_read_pointer(unsigned int read_index) 267 | { 268 | void* ptr = nullptr; 269 | switch (d_transfer_type) { 270 | case transfer_type::HOST_TO_DEVICE: 271 | case transfer_type::DEVICE_TO_DEVICE: 272 | // Read from "device" buffer 273 | ptr = &d_cuda_buf[read_index * d_sizeof_item]; 274 | break; 275 | 276 | case transfer_type::DEVICE_TO_HOST: 277 | // Read from host buffer 278 | ptr = &d_base[read_index * d_sizeof_item]; 279 | break; 280 | 281 | default: 282 | std::ostringstream msg; 283 | msg << "Unexpected context for cuda: " << d_transfer_type; 284 | GR_LOG_ERROR(d_logger, msg.str()); 285 | throw std::runtime_error(msg.str()); 286 | } 287 | 288 | return ptr; 289 | } 290 | 291 | bool cuda_buffer::input_blocked_callback(int items_required, 292 | int items_avail, 293 | unsigned read_index) 294 | { 295 | #ifdef BUFFER_DEBUG 296 | std::ostringstream msg; 297 | msg << "[" << this << "] " 298 | << "cuda [" << d_transfer_type << "] -- input_blocked_callback"; 299 | GR_LOG_DEBUG(d_logger, msg.str()); 300 | #endif 301 | 302 | bool rc = false; 303 | switch (d_transfer_type) { 304 | case transfer_type::HOST_TO_DEVICE: 305 | case transfer_type::DEVICE_TO_DEVICE: 306 | // Adjust "device" buffer 307 | rc = input_blocked_callback_logic(items_required, 308 | items_avail, 309 | read_index, 310 | d_cuda_buf, 311 | f_cuda_memcpy, 312 | f_cuda_memmove); 313 | break; 314 | 315 | case transfer_type::DEVICE_TO_HOST: 316 | // Adjust host buffer 317 | rc = input_blocked_callback_logic( 318 | items_required, items_avail, read_index, d_base, std::memcpy, std::memmove); 319 | break; 320 | 321 | default: 322 | std::ostringstream msg; 323 | msg << "Unexpected context for cuda: " << d_transfer_type; 324 | GR_LOG_ERROR(d_logger, msg.str()); 325 | throw std::runtime_error(msg.str()); 326 | } 327 | 328 | return rc; 329 | } 330 | 331 | bool cuda_buffer::output_blocked_callback(int output_multiple, bool force) 332 | { 333 | #ifdef BUFFER_DEBUG 334 | std::ostringstream msg; 335 | msg << "[" << this << "] " 336 | << "host_buffer [" << d_transfer_type << "] -- output_blocked_callback"; 337 | GR_LOG_DEBUG(d_logger, msg.str()); 338 | #endif 339 | 340 | bool rc = false; 341 | switch (d_transfer_type) { 342 | case transfer_type::HOST_TO_DEVICE: 343 | // Adjust host buffer 344 | rc = output_blocked_callback_logic(output_multiple, force, d_base, std::memmove); 345 | break; 346 | 347 | case transfer_type::DEVICE_TO_HOST: 348 | case transfer_type::DEVICE_TO_DEVICE: 349 | // Adjust "device" buffer 350 | rc = output_blocked_callback_logic( 351 | output_multiple, force, d_cuda_buf, f_cuda_memmove ); 352 | break; 353 | 354 | default: 355 | std::ostringstream msg; 356 | msg << "Unexpected context for cuda: " << d_transfer_type; 357 | GR_LOG_ERROR(d_logger, msg.str()); 358 | throw std::runtime_error(msg.str()); 359 | } 360 | 361 | return rc; 362 | } 363 | 364 | buffer_sptr cuda_buffer::make_buffer(int nitems, 365 | size_t sizeof_item, 366 | uint64_t downstream_lcm_nitems, 367 | uint32_t downstream_max_out_mult, 368 | block_sptr link, 369 | block_sptr buf_owner) 370 | { 371 | return buffer_sptr(new cuda_buffer(nitems, sizeof_item, downstream_lcm_nitems, 372 | downstream_max_out_mult, link, buf_owner)); 373 | } 374 | 375 | } // namespace gr 376 | -------------------------------------------------------------------------------- /lib/cuda_error.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void check_cuda_errors(cudaError_t rc) 4 | { 5 | if (rc) { 6 | std::cerr << "Operation returned code " << int(rc) << ": " << cudaGetErrorName(rc) 7 | << " -- " << cudaGetErrorString(rc); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /lib/load.cu: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // The block cuda file is just a wrapper for the kernels that will be launched in the work 6 | // function 7 | namespace gr { 8 | namespace cuda { 9 | namespace load_cu { 10 | __global__ void load_kernel(const uint8_t* in, uint8_t* out, int N, size_t load = 1) 11 | { 12 | int i = blockIdx.x * blockDim.x + threadIdx.x; 13 | if (i < N) { 14 | for (int x = 0; x < load; x++) { 15 | out[i] = in[i]; 16 | } 17 | } 18 | } 19 | 20 | void exec_kernel(const uint8_t* in, 21 | uint8_t* out, 22 | int grid_size, 23 | int block_size, 24 | int N, 25 | size_t load, 26 | cudaStream_t stream) 27 | { 28 | load_kernel<<>>(in, out, N, load); 29 | } 30 | 31 | void get_block_and_grid(int* minGrid, int* minBlock) 32 | { 33 | cudaOccupancyMaxPotentialBlockSize(minGrid, minBlock, load_kernel, 0, 0); 34 | } 35 | 36 | } // namespace load_cu 37 | } // namespace cuda 38 | } // namespace gr -------------------------------------------------------------------------------- /lib/load.cuh: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | namespace gr { 6 | namespace cuda { 7 | namespace load_cu { 8 | 9 | void exec_kernel( 10 | const uint8_t* in, uint8_t* out, int grid_size, int block_size, int N, size_t load, cudaStream_t stream); 11 | 12 | void get_block_and_grid(int* minGrid, int* minBlock); 13 | 14 | } // namespace multiply_const 15 | } // namespace blocks 16 | } // namespace gr -------------------------------------------------------------------------------- /lib/load_impl.cc: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2022 Josh Morman. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | #include "load_impl.h" 9 | #include 10 | #include 11 | 12 | #include "load.cuh" 13 | 14 | namespace gr { 15 | namespace cuda { 16 | 17 | load::sptr load::make(size_t iterations, size_t itemsize, bool use_cb) 18 | { 19 | return gnuradio::make_block_sptr(iterations, itemsize, use_cb); 20 | } 21 | 22 | 23 | /* 24 | * The private constructor 25 | */ 26 | load_impl::load_impl(size_t iterations, size_t itemsize, bool use_cb) 27 | : gr::sync_block("load", 28 | gr::io_signature::make(1, 1, itemsize), 29 | gr::io_signature::make(1, 1, itemsize)), 30 | d_iterations(iterations), 31 | d_itemsize(itemsize), 32 | d_use_cb(use_cb) 33 | { 34 | load_cu::get_block_and_grid(&d_min_grid_size, &d_block_size); 35 | d_logger->info("minGrid: {}, blockSize: {}", d_min_grid_size, d_block_size); 36 | cudaStreamCreate(&d_stream); 37 | 38 | if (use_cb) { 39 | set_input_signature(gr::io_signature::make(1, 1, itemsize, cuda_buffer::type)); 40 | set_output_signature(gr::io_signature::make(1, 1, itemsize, cuda_buffer::type)); 41 | } else { 42 | check_cuda_errors(cudaMalloc((void**)&d_dev_in, d_max_buffer_size)); 43 | check_cuda_errors(cudaMalloc((void**)&d_dev_out, d_max_buffer_size)); 44 | } 45 | } 46 | 47 | int load_impl::work(int noutput_items, 48 | gr_vector_const_void_star& input_items, 49 | gr_vector_void_star& output_items) 50 | { 51 | auto in = static_cast(input_items[0]); 52 | auto out = static_cast(output_items[0]); 53 | 54 | int gridSize = (noutput_items * d_itemsize + d_block_size - 1) / d_block_size; 55 | 56 | if (!d_use_cb) { 57 | check_cuda_errors(cudaMemcpyAsync(d_dev_in, 58 | in, 59 | noutput_items * d_itemsize, 60 | cudaMemcpyHostToDevice, 61 | d_stream)); 62 | 63 | load_cu::exec_kernel(d_dev_in, 64 | d_dev_out, 65 | gridSize, 66 | d_block_size, 67 | noutput_items * d_itemsize, 68 | d_iterations, 69 | d_stream); 70 | check_cuda_errors(cudaPeekAtLastError()); 71 | 72 | cudaMemcpyAsync(out, 73 | d_dev_out, 74 | noutput_items * d_itemsize, 75 | cudaMemcpyDeviceToHost, 76 | d_stream); 77 | 78 | } else { 79 | load_cu::exec_kernel(in, 80 | out, 81 | gridSize, 82 | d_block_size, 83 | noutput_items * d_itemsize, 84 | d_iterations, 85 | d_stream); 86 | check_cuda_errors(cudaPeekAtLastError()); 87 | } 88 | 89 | 90 | cudaStreamSynchronize(d_stream); 91 | 92 | // Tell runtime system how many output items we produced. 93 | return noutput_items; 94 | } 95 | 96 | } /* namespace cuda */ 97 | } // namespace gr 98 | -------------------------------------------------------------------------------- /lib/load_impl.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2022 Josh Morman. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | #ifndef INCLUDED_CUDA_LOAD_IMPL_H 9 | #define INCLUDED_CUDA_LOAD_IMPL_H 10 | 11 | #include 12 | #include 13 | 14 | namespace gr { 15 | namespace cuda { 16 | 17 | class load_impl : public load, public cuda_block 18 | { 19 | private: 20 | size_t d_iterations; 21 | size_t d_itemsize; 22 | bool d_use_cb; 23 | uint8_t *d_dev_in; 24 | uint8_t *d_dev_out; 25 | 26 | size_t d_max_buffer_size = 65536*8; 27 | public: 28 | load_impl(size_t iterations, size_t itemsize, bool use_cb = true); 29 | 30 | // Where all the action really happens 31 | int work(int noutput_items, 32 | gr_vector_const_void_star& input_items, 33 | gr_vector_void_star& output_items); 34 | }; 35 | 36 | } // namespace cuda 37 | } // namespace gr 38 | 39 | #endif /* INCLUDED_CUDA_LOAD_IMPL_H */ 40 | -------------------------------------------------------------------------------- /lib/multiply_const.cu: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | // This is the kernel that will get launched on the device 10 | template 11 | __global__ void kernel_multiply_const(const T* in, T* out, T k, int N) 12 | { 13 | int i = blockIdx.x * blockDim.x + threadIdx.x; 14 | if (i < N) { 15 | out[i] = in[i] * k; 16 | } 17 | } 18 | 19 | template <> 20 | __global__ void 21 | kernel_multiply_const>(const thrust::complex* in, 22 | thrust::complex* out, 23 | thrust::complex k, 24 | int N) 25 | { 26 | int i = blockIdx.x * blockDim.x + threadIdx.x; 27 | if (i < N) { 28 | out[i] = in[i] * k; 29 | } 30 | } 31 | 32 | // Kernel wrapper so that the GNU Radio code doesn't have to compile with nvcc 33 | template 34 | void exec_kernel_multiply_const(const T* in, 35 | T* out, 36 | T k, 37 | int grid_size, 38 | int block_size, 39 | size_t n, 40 | cudaStream_t stream) 41 | { 42 | kernel_multiply_const<<>>(in, out, k, n); 43 | check_cuda_errors(cudaGetLastError()); 44 | } 45 | 46 | template <> 47 | void exec_kernel_multiply_const>(const std::complex* in, 48 | std::complex* out, 49 | std::complex k, 50 | int grid_size, 51 | int block_size, 52 | size_t n, 53 | cudaStream_t stream) 54 | { 55 | kernel_multiply_const> 56 | <<>>((const thrust::complex*)in, 57 | (thrust::complex*)out, 58 | (thrust::complex)k, 59 | n); 60 | check_cuda_errors(cudaGetLastError()); 61 | } 62 | 63 | template 64 | void get_block_and_grid(int* minGrid, int* minBlock) 65 | { 66 | check_cuda_errors(cudaOccupancyMaxPotentialBlockSize( 67 | minGrid, minBlock, kernel_multiply_const, 0, 0)); 68 | } 69 | 70 | template <> 71 | void get_block_and_grid>(int* minGrid, int* minBlock) 72 | { 73 | check_cuda_errors(cudaOccupancyMaxPotentialBlockSize( 74 | minGrid, minBlock, kernel_multiply_const>, 0, 0)); 75 | } 76 | 77 | #define IMPLEMENT_KERNEL(T) \ 78 | template void get_block_and_grid(int*, int*); \ 79 | template void exec_kernel_multiply_const( \ 80 | const T*, T*, T, int, int, size_t, cudaStream_t); 81 | 82 | IMPLEMENT_KERNEL(int16_t) 83 | IMPLEMENT_KERNEL(int32_t) 84 | IMPLEMENT_KERNEL(float) 85 | IMPLEMENT_KERNEL(std::complex) -------------------------------------------------------------------------------- /lib/multiply_const_impl.cc: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2021 Josh Morman. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | #include "multiply_const_impl.h" 9 | #include 10 | #include 11 | #include 12 | 13 | template 14 | void exec_kernel_multiply_const(const T* in, 15 | T* out, 16 | T k, 17 | int grid_size, 18 | int block_size, 19 | size_t n, 20 | cudaStream_t stream); 21 | 22 | template 23 | void get_block_and_grid(int* minGrid, int* minBlock); 24 | 25 | 26 | namespace gr { 27 | namespace cuda { 28 | 29 | template 30 | typename multiply_const::sptr multiply_const::make(T k, size_t vlen) 31 | { 32 | return gnuradio::make_block_sptr>(k, vlen); 33 | } 34 | 35 | template 36 | multiply_const_impl::multiply_const_impl(T k, size_t vlen) 37 | : gr::sync_block("multiply_const", 38 | io_signature::make(1, 1, sizeof(T) * vlen, cuda_buffer::type), 39 | io_signature::make(1, 1, sizeof(T) * vlen, cuda_buffer::type)), 40 | d_k(k), 41 | d_vlen(vlen) 42 | { 43 | get_block_and_grid(&d_min_grid_size, &d_block_size); 44 | check_cuda_errors(cudaStreamCreate(&d_stream)); 45 | } 46 | 47 | template 48 | int multiply_const_impl::work(int noutput_items, 49 | gr_vector_const_void_star& input_items, 50 | gr_vector_void_star& output_items) 51 | { 52 | auto in = static_cast(input_items[0]); 53 | auto out = static_cast(output_items[0]); 54 | int gridSize = (noutput_items + d_block_size - 1) / d_block_size; 55 | exec_kernel_multiply_const(in, 56 | out, 57 | d_k, 58 | gridSize, 59 | d_block_size, 60 | noutput_items, 61 | d_stream); 62 | 63 | cudaStreamSynchronize(d_stream); 64 | 65 | // Tell runtime system how many output items we produced. 66 | return noutput_items; 67 | } 68 | 69 | template class multiply_const; 70 | template class multiply_const; 71 | template class multiply_const; 72 | template class multiply_const; 73 | 74 | } /* namespace cuda */ 75 | } /* namespace gr */ 76 | -------------------------------------------------------------------------------- /lib/multiply_const_impl.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2021 Josh Morman. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | #ifndef INCLUDED_CUDA_MULTIPLY_CONST_IMPL_H 9 | #define INCLUDED_CUDA_MULTIPLY_CONST_IMPL_H 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace gr { 17 | namespace cuda { 18 | 19 | template 20 | class multiply_const_impl : public multiply_const, public cuda_block 21 | { 22 | 23 | private: 24 | 25 | T d_k; 26 | const size_t d_vlen; 27 | 28 | public: 29 | multiply_const_impl(T k, size_t vlen); 30 | 31 | T k() const override { return d_k; } 32 | void set_k(T k) override { d_k = k; } 33 | 34 | int work(int noutput_items, 35 | gr_vector_const_void_star& input_items, 36 | gr_vector_void_star& output_items) override; 37 | }; 38 | 39 | } // namespace cuda 40 | } // namespace gr 41 | 42 | #endif /* INCLUDED_CUDA_MULTIPLY_CONST_IMPL_H */ 43 | -------------------------------------------------------------------------------- /python/cuda/.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.pyc 3 | *.pyo 4 | build*/ 5 | examples/grc/*.py 6 | -------------------------------------------------------------------------------- /python/cuda/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Free Software Foundation, Inc. 2 | # 3 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 4 | # This file is a part of gr-cuda 5 | # 6 | # SPDX-License-Identifier: GPL-3.0-or-later 7 | # 8 | 9 | ######################################################################## 10 | # Include python install macros 11 | ######################################################################## 12 | include(GrPython) 13 | if(NOT PYTHONINTERP_FOUND) 14 | return() 15 | endif() 16 | 17 | add_subdirectory(bindings) 18 | 19 | ######################################################################## 20 | # Install python sources 21 | ######################################################################## 22 | GR_PYTHON_INSTALL( 23 | FILES 24 | __init__.py 25 | DESTINATION ${GR_PYTHON_DIR}/gnuradio/cuda 26 | ) 27 | 28 | ######################################################################## 29 | # Handle the unit tests 30 | ######################################################################## 31 | include(GrTest) 32 | 33 | set(GR_TEST_TARGET_DEPS gnuradio-cuda) 34 | GR_ADD_TEST(qa_copy ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_copy.py) 35 | GR_ADD_TEST(qa_multiply_const ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_multiply_const.py) 36 | 37 | # Create a package directory that tests can import. It includes everything 38 | # from `python/`. 39 | add_custom_target( 40 | copy_module_for_tests ALL 41 | COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR} 42 | ${CMAKE_BINARY_DIR}/test_modules/gnuradio/cuda/ 43 | ) 44 | 45 | GR_ADD_TEST(qa_load ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_load.py) 46 | -------------------------------------------------------------------------------- /python/cuda/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2008,2009 Free Software Foundation, Inc. 3 | # 4 | # SPDX-License-Identifier: GPL-3.0-or-later 5 | # 6 | 7 | # The presence of this file turns this directory into a Python package 8 | 9 | ''' 10 | This is the GNU Radio CUDA module. Place your Python package 11 | description here (python/__init__.py). 12 | ''' 13 | import os 14 | 15 | # import pybind11 generated symbols into the cuda namespace 16 | try: 17 | # this might fail if the module is python-only 18 | from .cuda_python import * 19 | except ModuleNotFoundError: 20 | pass 21 | 22 | # import any pure python here 23 | # 24 | -------------------------------------------------------------------------------- /python/cuda/bindings/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Free Software Foundation, Inc. 2 | # 3 | # This file is part of GNU Radio 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | # 7 | 8 | ######################################################################## 9 | # Check if there is C++ code at all 10 | ######################################################################## 11 | if(NOT cuda_sources) 12 | MESSAGE(STATUS "No C++ sources... skipping python bindings") 13 | return() 14 | endif(NOT cuda_sources) 15 | 16 | ######################################################################## 17 | # Check for pygccxml 18 | ######################################################################## 19 | GR_PYTHON_CHECK_MODULE_RAW( 20 | "pygccxml" 21 | "import pygccxml" 22 | PYGCCXML_FOUND 23 | ) 24 | 25 | include(GrPybind) 26 | 27 | ######################################################################## 28 | # Python Bindings 29 | ######################################################################## 30 | 31 | list(APPEND cuda_python_files 32 | copy_python.cc 33 | multiply_const_python.cc 34 | load_python.cc python_bindings.cc) 35 | 36 | GR_PYBIND_MAKE_OOT(cuda 37 | ../../.. 38 | gr::cuda 39 | "${cuda_python_files}") 40 | 41 | # copy in bindings .so file for use in QA test module 42 | add_custom_target( 43 | copy_bindings_for_tests ALL 44 | COMMAND 45 | ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_BINARY_DIR}/*.so" 46 | ${CMAKE_BINARY_DIR}/test_modules/gnuradio/cuda/ 47 | DEPENDS cuda_python) 48 | 49 | install(TARGETS cuda_python DESTINATION ${GR_PYTHON_DIR}/gnuradio/cuda COMPONENT pythonapi) 50 | -------------------------------------------------------------------------------- /python/cuda/bindings/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnuradio/gr-cuda/d373c1b2e5f8707d8798c57be5395bdac1c73011/python/cuda/bindings/README.md -------------------------------------------------------------------------------- /python/cuda/bindings/bind_oot_file.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | import argparse 3 | import os 4 | from gnuradio.bindtool import BindingGenerator 5 | import pathlib 6 | import sys 7 | import tempfile 8 | 9 | parser = argparse.ArgumentParser(description='Bind a GR Out of Tree Block') 10 | parser.add_argument('--module', type=str, 11 | help='Name of gr module containing file to bind (e.g. fft digital analog)') 12 | 13 | parser.add_argument('--output_dir', default=tempfile.gettempdir(), 14 | help='Output directory of generated bindings') 15 | parser.add_argument('--prefix', help='Prefix of Installed GNU Radio') 16 | parser.add_argument('--src', help='Directory of gnuradio source tree', 17 | default=os.path.dirname(os.path.abspath(__file__)) + '/../../..') 18 | 19 | parser.add_argument( 20 | '--filename', help="File to be parsed") 21 | 22 | parser.add_argument( 23 | '--defines', help='Set additional defines for precompiler', default=(), nargs='*') 24 | parser.add_argument( 25 | '--include', help='Additional Include Dirs, separated', default=(), nargs='*') 26 | 27 | parser.add_argument( 28 | '--status', help='Location of output file for general status (used during cmake)', default=None 29 | ) 30 | parser.add_argument( 31 | '--flag_automatic', default='0' 32 | ) 33 | parser.add_argument( 34 | '--flag_pygccxml', default='0' 35 | ) 36 | 37 | args = parser.parse_args() 38 | 39 | prefix = args.prefix 40 | output_dir = args.output_dir 41 | defines = tuple(','.join(args.defines).split(',')) 42 | includes = ','.join(args.include) 43 | name = args.module 44 | 45 | namespace = ['gr', name] 46 | prefix_include_root = name 47 | 48 | 49 | with warnings.catch_warnings(): 50 | warnings.filterwarnings("ignore", category=DeprecationWarning) 51 | 52 | bg = BindingGenerator(prefix, namespace, 53 | prefix_include_root, output_dir, define_symbols=defines, addl_includes=includes, 54 | catch_exceptions=False, write_json_output=False, status_output=args.status, 55 | flag_automatic=True if args.flag_automatic.lower() in [ 56 | '1', 'true'] else False, 57 | flag_pygccxml=True if args.flag_pygccxml.lower() in ['1', 'true'] else False) 58 | bg.gen_file_binding(args.filename) 59 | -------------------------------------------------------------------------------- /python/cuda/bindings/copy_python.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GNU Radio 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | /***********************************************************************************/ 11 | /* This file is automatically generated using bindtool and can be manually 12 | * edited */ 13 | /* The following lines can be configured to regenerate this file during cmake */ 14 | /* If manual edits are made, the following tags should be modified accordingly. 15 | */ 16 | /* BINDTOOL_GEN_AUTOMATIC(0) */ 17 | /* BINDTOOL_USE_PYGCCXML(0) */ 18 | /* BINDTOOL_HEADER_FILE(copy.h) */ 19 | /* BINDTOOL_HEADER_FILE_HASH(2ba0497b0f20abc0f60cb1053aa64cde) */ 20 | /***********************************************************************************/ 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | namespace py = pybind11; 27 | 28 | #include 29 | // pydoc.h is automatically generated in the build directory 30 | #include 31 | 32 | void bind_copy(py::module &m) { 33 | 34 | using copy = ::gr::cuda::copy; 35 | 36 | py::class_>(m, "copy", D(copy)) 38 | 39 | .def(py::init(©::make), py::arg("itemsize"), D(copy, make)) 40 | 41 | ; 42 | } 43 | -------------------------------------------------------------------------------- /python/cuda/bindings/docstrings/README.md: -------------------------------------------------------------------------------- 1 | This directory stores templates for docstrings that are scraped from the include header files for each block -------------------------------------------------------------------------------- /python/cuda/bindings/docstrings/copy_pydoc_template.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GNU Radio 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | #include "pydoc_macros.h" 10 | #define D(...) DOC(gr,cuda, __VA_ARGS__ ) 11 | /* 12 | This file contains placeholders for docstrings for the Python bindings. 13 | Do not edit! These were automatically extracted during the binding process 14 | and will be overwritten during the build process 15 | */ 16 | 17 | 18 | 19 | static const char *__doc_gr_cuda_copy = R"doc()doc"; 20 | 21 | 22 | static const char *__doc_gr_cuda_copy_copy = R"doc()doc"; 23 | 24 | 25 | static const char *__doc_gr_cuda_copy_make = R"doc()doc"; 26 | 27 | 28 | -------------------------------------------------------------------------------- /python/cuda/bindings/docstrings/load_pydoc_template.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GNU Radio 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | #include "pydoc_macros.h" 10 | #define D(...) DOC(gr,cuda, __VA_ARGS__ ) 11 | /* 12 | This file contains placeholders for docstrings for the Python bindings. 13 | Do not edit! These were automatically extracted during the binding process 14 | and will be overwritten during the build process 15 | */ 16 | 17 | 18 | 19 | static const char *__doc_gr_cuda_load = R"doc()doc"; 20 | 21 | 22 | static const char *__doc_gr_cuda_load_load = R"doc()doc"; 23 | 24 | 25 | static const char *__doc_gr_cuda_load_make = R"doc()doc"; 26 | 27 | 28 | -------------------------------------------------------------------------------- /python/cuda/bindings/docstrings/multiply_const_pydoc_template.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GNU Radio 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | #include "pydoc_macros.h" 10 | #define D(...) DOC(gr,cuda, __VA_ARGS__ ) 11 | /* 12 | This file contains placeholders for docstrings for the Python bindings. 13 | Do not edit! These were automatically extracted during the binding process 14 | and will be overwritten during the build process 15 | */ 16 | 17 | 18 | 19 | static const char *__doc_gr_cuda_multiply_const = R"doc()doc"; 20 | 21 | 22 | static const char *__doc_gr_cuda_multiply_const_multiply_const = R"doc()doc"; 23 | 24 | 25 | static const char *__doc_gr_cuda_multiply_const_make = R"doc()doc"; 26 | 27 | 28 | -------------------------------------------------------------------------------- /python/cuda/bindings/header_utils.py: -------------------------------------------------------------------------------- 1 | # Utilities for reading values in header files 2 | 3 | from argparse import ArgumentParser 4 | import re 5 | 6 | 7 | class PybindHeaderParser: 8 | def __init__(self, pathname): 9 | with open(pathname, 'r') as f: 10 | self.file_txt = f.read() 11 | 12 | def get_flag_automatic(self): 13 | # p = re.compile(r'BINDTOOL_GEN_AUTOMATIC\(([^\s])\)') 14 | # m = p.search(self.file_txt) 15 | m = re.search(r'BINDTOOL_GEN_AUTOMATIC\(([^\s])\)', self.file_txt) 16 | if (m and m.group(1) == '1'): 17 | return True 18 | else: 19 | return False 20 | 21 | def get_flag_pygccxml(self): 22 | # p = re.compile(r'BINDTOOL_USE_PYGCCXML\(([^\s])\)') 23 | # m = p.search(self.file_txt) 24 | m = re.search(r'BINDTOOL_USE_PYGCCXML\(([^\s])\)', self.file_txt) 25 | if (m and m.group(1) == '1'): 26 | return True 27 | else: 28 | return False 29 | 30 | def get_header_filename(self): 31 | # p = re.compile(r'BINDTOOL_HEADER_FILE\(([^\s]*)\)') 32 | # m = p.search(self.file_txt) 33 | m = re.search(r'BINDTOOL_HEADER_FILE\(([^\s]*)\)', self.file_txt) 34 | if (m): 35 | return m.group(1) 36 | else: 37 | return None 38 | 39 | def get_header_file_hash(self): 40 | # p = re.compile(r'BINDTOOL_HEADER_FILE_HASH\(([^\s]*)\)') 41 | # m = p.search(self.file_txt) 42 | m = re.search(r'BINDTOOL_HEADER_FILE_HASH\(([^\s]*)\)', self.file_txt) 43 | if (m): 44 | return m.group(1) 45 | else: 46 | return None 47 | 48 | def get_flags(self): 49 | return f'{self.get_flag_automatic()};{self.get_flag_pygccxml()};{self.get_header_filename()};{self.get_header_file_hash()};' 50 | 51 | 52 | def argParse(): 53 | """Parses commandline args.""" 54 | desc = 'Reads the parameters from the comment block in the pybind files' 55 | parser = ArgumentParser(description=desc) 56 | 57 | parser.add_argument("function", help="Operation to perform on comment block of pybind file", choices=[ 58 | "flag_auto", "flag_pygccxml", "header_filename", "header_file_hash", "all"]) 59 | parser.add_argument( 60 | "pathname", help="Pathname of pybind c++ file to read, e.g. blockname_python.cc") 61 | 62 | return parser.parse_args() 63 | 64 | 65 | if __name__ == "__main__": 66 | # Parse command line options and set up doxyxml. 67 | args = argParse() 68 | 69 | pbhp = PybindHeaderParser(args.pathname) 70 | 71 | if args.function == "flag_auto": 72 | print(pbhp.get_flag_automatic()) 73 | elif args.function == "flag_pygccxml": 74 | print(pbhp.get_flag_pygccxml()) 75 | elif args.function == "header_filename": 76 | print(pbhp.get_header_filename()) 77 | elif args.function == "header_file_hash": 78 | print(pbhp.get_header_file_hash()) 79 | elif args.function == "all": 80 | print(pbhp.get_flags()) 81 | -------------------------------------------------------------------------------- /python/cuda/bindings/load_python.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GNU Radio 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | /***********************************************************************************/ 11 | /* This file is automatically generated using bindtool and can be manually edited */ 12 | /* The following lines can be configured to regenerate this file during cmake */ 13 | /* If manual edits are made, the following tags should be modified accordingly. */ 14 | /* BINDTOOL_GEN_AUTOMATIC(0) */ 15 | /* BINDTOOL_USE_PYGCCXML(0) */ 16 | /* BINDTOOL_HEADER_FILE(load.h) */ 17 | /* BINDTOOL_HEADER_FILE_HASH(6b8b88e16cc7497e8aa51711019ffa7d) */ 18 | /***********************************************************************************/ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | namespace py = pybind11; 25 | 26 | #include 27 | // pydoc.h is automatically generated in the build directory 28 | #include 29 | 30 | void bind_load(py::module& m) 31 | { 32 | 33 | using load = ::gr::cuda::load; 34 | 35 | 36 | py::class_>(m, "load", D(load)) 38 | 39 | .def(py::init(&load::make), 40 | py::arg("iterations"), 41 | py::arg("itemsize"), 42 | py::arg("use_cb") = true, 43 | D(load,make) 44 | ) 45 | 46 | 47 | 48 | 49 | ; 50 | 51 | 52 | 53 | 54 | } 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /python/cuda/bindings/multiply_const_python.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GNU Radio 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | /***********************************************************************************/ 11 | /* This file is automatically generated using bindtool and can be manually edited */ 12 | /* The following lines can be configured to regenerate this file during cmake */ 13 | /* If manual edits are made, the following tags should be modified accordingly. */ 14 | /* BINDTOOL_GEN_AUTOMATIC(0) */ 15 | /* BINDTOOL_USE_PYGCCXML(0) */ 16 | /* BINDTOOL_HEADER_FILE(multiply_const.h) */ 17 | /* BINDTOOL_HEADER_FILE_HASH(b3dc8adec5b21bbf727c2163d537d839) */ 18 | /***********************************************************************************/ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | namespace py = pybind11; 25 | 26 | #include 27 | // pydoc.h is automatically generated in the build directory 28 | #include 29 | 30 | template 31 | void bind_multiply_const_template(py::module& m, const char* classname) 32 | { 33 | using multiply_const = gr::cuda::multiply_const; 34 | 35 | py::class_>(m, classname) 40 | .def(py::init(&gr::cuda::multiply_const::make), 41 | py::arg("k"), 42 | py::arg("vlen") = 1) 43 | .def("k", &multiply_const::k) 44 | .def("set_k", &multiply_const::set_k, py::arg("k")); 45 | } 46 | 47 | void bind_multiply_const(py::module& m) 48 | { 49 | bind_multiply_const_template(m, "multiply_const_ss"); 50 | bind_multiply_const_template(m, "multiply_const_ii"); 51 | bind_multiply_const_template(m, "multiply_const_ff"); 52 | bind_multiply_const_template(m, "multiply_const_cc"); 53 | } 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /python/cuda/bindings/python_bindings.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GNU Radio 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later 7 | * 8 | */ 9 | 10 | #include 11 | 12 | #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION 13 | #include 14 | 15 | namespace py = pybind11; 16 | 17 | // Headers for binding functions 18 | /**************************************/ 19 | // The following comment block is used for 20 | // gr_modtool to insert function prototypes 21 | // Please do not delete 22 | /**************************************/ 23 | // BINDING_FUNCTION_PROTOTYPES( 24 | void bind_copy(py::module &m); 25 | void bind_multiply_const(py::module& m); 26 | void bind_load(py::module& m); 27 | // ) END BINDING_FUNCTION_PROTOTYPES 28 | 29 | 30 | // We need this hack because import_array() returns NULL 31 | // for newer Python versions. 32 | // This function is also necessary because it ensures access to the C API 33 | // and removes a warning. 34 | void* init_numpy() 35 | { 36 | import_array(); 37 | return NULL; 38 | } 39 | 40 | PYBIND11_MODULE(cuda_python, m) 41 | { 42 | // Initialize the numpy C API 43 | // (otherwise we will see segmentation faults) 44 | init_numpy(); 45 | 46 | // Allow access to base block methods 47 | py::module::import("gnuradio.gr"); 48 | 49 | /**************************************/ 50 | // The following comment block is used for 51 | // gr_modtool to insert binding function calls 52 | // Please do not delete 53 | /**************************************/ 54 | // BINDING_FUNCTION_CALLS( 55 | bind_copy(m); 56 | bind_multiply_const(m); 57 | bind_load(m); 58 | // ) END BINDING_FUNCTION_CALLS 59 | } -------------------------------------------------------------------------------- /python/cuda/qa_copy.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2021 Josh. 5 | # 6 | # SPDX-License-Identifier: GPL-3.0-or-later 7 | # 8 | 9 | from gnuradio import gr, gr_unittest 10 | from gnuradio import blocks 11 | try: 12 | from gnuradio.cuda import copy 13 | except ImportError: 14 | import os 15 | import sys 16 | dirname, filename = os.path.split(os.path.abspath(__file__)) 17 | sys.path.append(os.path.join(dirname, "bindings")) 18 | from gnuradio.cuda import copy 19 | 20 | class qa_copy(gr_unittest.TestCase): 21 | 22 | def setUp(self): 23 | self.tb = gr.top_block() 24 | 25 | def tearDown(self): 26 | self.tb = None 27 | 28 | def test_instance(self): 29 | instance = copy(gr.sizeof_gr_complex) 30 | 31 | def test_001_descriptive_test_name(self): 32 | nsamples = 10000 33 | 34 | input_data = list(range(nsamples)) 35 | src = blocks.vector_source_f(input_data, False) 36 | op = copy(gr.sizeof_float) 37 | snk = blocks.vector_sink_f() 38 | 39 | self.tb.connect(src, op, snk) 40 | 41 | self.tb.run() 42 | 43 | 44 | self.assertEqual(snk.data(), input_data) 45 | 46 | 47 | if __name__ == '__main__': 48 | gr_unittest.run(qa_copy) 49 | -------------------------------------------------------------------------------- /python/cuda/qa_load.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2022 Josh Morman. 5 | # 6 | # SPDX-License-Identifier: GPL-3.0-or-later 7 | # 8 | 9 | from gnuradio import gr, gr_unittest 10 | # from gnuradio import blocks 11 | try: 12 | from gnuradio.cuda import load 13 | except ImportError: 14 | import os 15 | import sys 16 | dirname, filename = os.path.split(os.path.abspath(__file__)) 17 | sys.path.append(os.path.join(dirname, "bindings")) 18 | from gnuradio.cuda import load 19 | 20 | class qa_load(gr_unittest.TestCase): 21 | 22 | def setUp(self): 23 | self.tb = gr.top_block() 24 | 25 | def tearDown(self): 26 | self.tb = None 27 | 28 | def test_instance(self): 29 | # FIXME: Test will fail until you pass sensible arguments to the constructor 30 | instance = load() 31 | 32 | def test_001_descriptive_test_name(self): 33 | # set up fg 34 | self.tb.run() 35 | # check data 36 | 37 | 38 | if __name__ == '__main__': 39 | gr_unittest.run(qa_load) 40 | -------------------------------------------------------------------------------- /python/cuda/qa_multiply_const.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2021 Josh Morman. 5 | # 6 | # SPDX-License-Identifier: GPL-3.0-or-later 7 | # 8 | 9 | from gnuradio import gr, gr_unittest 10 | from gnuradio import blocks 11 | try: 12 | from gnuradio.cuda import multiply_const_ff 13 | except ImportError: 14 | import os 15 | import sys 16 | dirname, filename = os.path.split(os.path.abspath(__file__)) 17 | sys.path.append(os.path.join(dirname, "bindings")) 18 | from gnuradio.cuda import multiply_const_ff 19 | 20 | class qa_multiply_const(gr_unittest.TestCase): 21 | 22 | def setUp(self): 23 | self.tb = gr.top_block() 24 | 25 | def tearDown(self): 26 | self.tb = None 27 | 28 | def test_instance(self): 29 | instance = multiply_const_ff(2.0, 1) 30 | 31 | def test_001_descriptive_test_name(self): 32 | # set up fg 33 | input_data = list(range(100000)) 34 | expected_data = [x*2.0*3.0 for x in input_data] 35 | src = blocks.vector_source_f(input_data, False) 36 | op1 = multiply_const_ff(2.0) 37 | op2 = multiply_const_ff(3.0) 38 | snk = blocks.vector_sink_f() 39 | self.tb.connect(src, op1, op2, snk) 40 | self.tb.run() 41 | self.assertEqual(snk.data(), expected_data) 42 | 43 | if __name__ == '__main__': 44 | gr_unittest.run(qa_multiply_const) 45 | --------------------------------------------------------------------------------