{"id":15360897,"url":"https://github.com/takagi/avm","last_synced_at":"2025-04-14T06:45:36.389Z","repository":{"id":142531533,"uuid":"63256582","full_name":"takagi/avm","owner":"takagi","description":"Efficient and expressive arrayed vector math library with multi-threading and CUDA support in Common Lisp.","archived":false,"fork":false,"pushed_at":"2021-08-16T08:15:04.000Z","size":192,"stargazers_count":54,"open_issues_count":2,"forks_count":4,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-03-27T20:21:45.376Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Common Lisp","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/takagi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2016-07-13T15:12:32.000Z","updated_at":"2024-11-26T23:30:34.000Z","dependencies_parsed_at":null,"dependency_job_id":"a8e7ad38-15a4-4db4-ba41-06ac343c5f93","html_url":"https://github.com/takagi/avm","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/takagi%2Favm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/takagi%2Favm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/takagi%2Favm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/takagi%2Favm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/takagi","download_url":"https://codeload.github.com/takagi/avm/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248837269,"owners_count":21169373,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-01T12:52:11.813Z","updated_at":"2025-04-14T06:45:36.343Z","avatar_url":"https://github.com/takagi.png","language":"Common Lisp","readme":"# AVM - Arrayed Vector Math library\n\nEfficient and expressive arrayed vector math library with multi-threading and CUDA support in Common Lisp.\n\n```common-lisp\n(defkernel mandelbrot (xs)\n  (labels ((aux (x y a b m)\n             (if (\u003c m 100)\n                 (let ((x1 (- (* x x) (* y y) a))\n                       (y1 (- (* 2.0 x y) b)))\n                   (if (\u003e (+ (* x1 x1) (* y1 y1)) 4.0)\n                       m\n                       (aux x1 y1 a b (+ m 1))))\n                 0)))\n    (let ((a (/ (float (- (mod i 2048) 512)) 1024.0))\n          (b (/ (float (- (/ i 2048) 1024)) 1024.0)))\n      (setf (aref xs i) (aux 0.0 0.0 a b 1)))))\n\n(defun draw-mandelbrot (pathname xs)\n  (with-open-file (out pathname :direction :output\n                                :if-does-not-exist :create\n                                :if-exists :supersede)\n    (write-line \"P2\" out)\n    (write-line \"2048 2048\" out)\n    (write-line \"255\" out)\n    (dotimes (i (* 2048 2048))\n      (princ (min 255 (* 8 (array-aref xs i))) out)\n      (terpri out))))\n\n(defun main (\u0026optional dev-id)\n  (with-cuda (dev-id)\n    (with-arrays ((xs int (* 2048 2048)))\n      (mandelbrot xs)\n      (draw-mandelbrot #P\"./mandelbrot.pgm\" xs))))\n```\n\n## Benchmark\n\nAVM's kernel functions run **almost as fast as equivalent C/C++ codes** with SBCL Common Lisp compiler. And we can easily make them run in parallel with just specifying the number of threads we use. Here shows a benchmark of computing 2048x2048 Mandelbrot set and 32768 bodies N-body simulation.\n\n![Benchmark](https://docs.google.com/spreadsheets/d/1_-_ucZTxqWXt1lqLOBoNQnMF5Us6ft3UMH9GT2wxWTM/pubchart?oid=414899701\u0026format=image)\n\nAdditionally, AVM provides Nvidia CUDA support so we can enormously accelerate computing kernel functions with GPUs.\n\n![Benchmark with CUDA](https://docs.google.com/spreadsheets/d/1_-_ucZTxqWXt1lqLOBoNQnMF5Us6ft3UMH9GT2wxWTM/pubchart?oid=1016247054\u0026format=image)\n\nThese benchmarks are measured on the following environment:\n\n- gcc 4.8.4\n- SBCL 1.3.3\n- Intel Celeron CPU G3900 @ 2.80GHz\n- Nvidia GeForce GTX 750 Ti\n- Linux ubuntu 4.2.0-41-generic x86_64\n\n## Usage\n\nTo be described.\n\n## Installation\n\nTo be described.\n\n## API\n\n### [Macro] defkernel\n\n    DEFKERNEL name args body\n\nDefines a kernel function. A defined kernel function is callable as if it is an ordinal Common Lisp function except that it may accept `:size` keyword parameter that specifies array size to be processed. If it is not given, the size of the first array in arguments is used. The `:size` keyword parameter is for the case that you want to pass arrays with various sizes and use the size of array that does not appear first in arguments. You may use built-in variables `i` and `n` in kernel functions, which contain the index and the size of array the kernel function processes respectively.\n\n**Example:**\n\n```common-lisp\n(defkernel fill-one (xs a)\n  (setf (aref xs i) 1))\n\n(with-array (xs int 1000)\n  (fill-one xs))\n```\n\n### [Special Variable] \\*compile-on-runtime\\*\n\nDelays AVM kernel function compilation to runtime if not `nil`. Otherwise, AVM kernel functions are compiled at compile time. Delaying compilation to runtime is useful, at least on SBCL, for debuging AVM kernel definitions because it makes CL debugger show backtrace when they have some errors.\n\n**Example:**\n\n```common-lisp\n(setf *compile-on-runtime* t)\n(defkernel some-error ()\n  (+ 1 1.0))                            ; AVM compile error showing backtrace\n```\n\n### [Macro] defkernel-macro\n\n    DEFKERNEL-MACRO name args \u0026body body =\u003e name\n\nDefines `name` as a macro by associating a macro function with that `name` in the global environment.\n\n**Examples:**\n\n```common-lisp\n(defkernel-macro mac1 (a b)\n  `(+ ,a (* ,b 3)))\n\n(defkernel fill-with-mac1 (xs a b)\n  (setf (aref xs i) (mac1 a b)))\n```\n\n### [Function] expand-macro, expand-macro-1\n\n    EXPAND-MACRO\n    EXPAND-MACRO-1\n\nTo be described.\n\n### [Macro] defkernel-global\n\n    DEFKERNEL-GROBAL\n\nTo be described.\n\n### [Macro] defkernel-constant\n\n    DEFKERNEL-CONSTANT\n\nTo be described.\n\n### [Macro] defkernel-symbol-macro\n\n    DEFKERNEL-SYMBOL-MACRO\n\nTo be described.\n\n### [Function] alloc-array\n\n    ALLOC-ARRAY type size =\u003e array\n\nAllocates an AVM array with specified `type` and `size`. `type` is a AVM type that means the array's base type and `size` is a positive integer that indicates the size of the array. For now, AVM supports one-dimensional array only. If CUDA is not available, memory area for CUDA is not allocated. `alloc-array`ed array should be freed with `free-array`. For convenience, `with-array` macro and `with-arrays` macro are provided.\n\n**Example:**\n\n```common-lisp\n(with-cuda (0)\n  (let ((xs (alloc-array 'int 100)))\n    (unwind-protect\n        (do-something-with xs)\n      (free-array xs))))\n```\n\n### [Function] free-array\n\n    FREE-ARRAY array =\u003e No value\n\nFrees the given `array`. Does nothing if `array` is already freed.\n\n**Example:**\n\n```common-lisp\n(with-cuda (0)\n  (let ((xs (alloc-array 'int 100)))\n    (unwind-protect\n        (do-something-with xs)\n      (free-array xs))))\n```\n\n### [Macro] with-array, with-arrays\n\n    WITH-ARRAY (var type size) body\n    WITH-ARRAYS ({(var type size)}*) body\n\nBinds `var` to an AVM array allocated using `alloc-array` applied to the given `type` and `size` during `body`. The array is freed using `free-alloc` when `with-array` exists. `with-arrays` is a plural form of `with-array`.\n\n**Example:**\n\n```common-lisp\n(with-cuda (0)\n  (with-array (xs int 100)\n    (do-something-with xs)))\n```\n\n### [Function] array-size\n\n    ARRAY-SIZE array =\u003e size\n\nReturns the size of given array.\n\n**Example:**\n\n```common-lisp\n(with-array (xs int 100)\n  (array-size xs))\n=\u003e 100\n```\n\n### [Accessor] array-aref\n\n    ARRAY-AREF array index =\u003e element\n    SETF (ARRAY-AREF array index) new-element\n\nAccesses `array`'s element specified by `index`. When `array`'s base type is of vector types, `array-aref` and `setf array-aref` handles values whose size is its base type's size. For example, `array-aref` and `setf array-aref` for an array of base type `float4` handles values of type `(values single-float single-float single-float single-float)`.\n\nIf CUDA is available, data on device memory is lazily synchronized before accessing elements of `array`, it is only if data on device memory is updated so data on host memory is out-of-date.\n\n**Example:**\n\n```common-lisp\n(with-array (xs int2 100)\n  (initialize-with-ones xs)\n  (array-aref xs 0))\n=\u003e (values 1 1)\n\n(with-array (xs int2 100)\n  (setf (array-aref xs 0) (values 1 1))\n  (array-aref xs 0))\n=\u003e (values 1 1)\n\n(with-cuda (0)\n  (with-array (xs int2 100)\n    (fill-ones xs)                      ; Ones filled on GPU.\n    (array-aref xs 0)))                 ; Lazily synchronized to host.\n=\u003e (values 1 1)\n```\n\n### [Macro] with-cuda\n\n    WITH-CUDA (dev-id) body\n\nInitializes CUDA and keeps a CUDA context during `body`. `dev-id` is passed to `cl-cuda:get-cuda-device` function to get device handler. If `dev-id` is `nil`, AVM uses Lisp backend so `WITH-CUDA` has no effect. In other words, you can switch if you use CUDA or not by `dev-id`.\n\n**Example:**\n\n```common-lisp\n(defkernel do-something (xs)\n  ...)\n\n(with-cuda (0)\n  (with-array (xs int 100)\n    (do-something xs)))                 ; Processed on GPU.\n\n(with-cuda (nil)\n  (with-array (xs int 100)\n    (do-something xs)))                 ; Processed on CPU.\n```\n\n### [Special Variable] \\*use-cuda-p\\*\n\nIn `with-cuda` macro's context, specifies if CUDA is used or not. The default value in `with-cuda` context is `t`. For detail, see [CUDA state](#cuda-state).\n\n**Example:**\n\n```common-lisp\n(with-cuda (0)\n  (with-array (xs int 100)\n    (do-something xs)                   ; Processed on GPU.\n    (let ((*use-cuda-p* nil))\n      (do-something xs))))              ; Processed on CPU.\n```\n\n### [Function] synchronize\n\n    SYNCHRONIZE\n\nExplicitly synchronizes CUDA context with `cl-cuda:synchronize-context`. This function is useful in case that you want to get timing data of CUDA kernel launching with `time` macro because CUDA kernel functions are executed asynchronously so it passes through `time` form in a moment without it. It does nothing if CUDA is not available.\n\n**Example:**\n\n```common-lisp\n(with-cuda (0)\n  (time\n    (progn\n      (do-something)\n      (synchronize))))\n```\n\n### [Special Variable] \\*use-thread-p\\*\n\nTo be described.\n\n### [Special Variable] \\*number-of-threads\\*\n\nTo be described.\n\n## Kernel Description Language\n\n### [Type] int, int2, int3, int4\n\nInteger type `int` and its derived vector types.\n\n### [Type] float, float2, float3, float4\n\nSingle precision floating point type `float` and its derived vector types.\n\n### [Type] double, double2, double3, double4\n\nDouble precision floating point type `double` and its derived vector types.\n\n### [Syntax] the\n\n    THE type form =\u003e result\n\n`the` specifies the value returned by `form` is of the type specified by `type`.\n\n**Example:**\n\n```common-lisp\n(flet ((identity (x)\n         (the int x)))\n  (identity 42))\n=\u003e 42\n```\n\n### [Syntax] if\n\n    IF test-form then-form else-form =\u003e result\n\n`if` allows the evaluation of a form to be dependent on a single `test-form`. First `test-form` is evaluated. If the result is `true`, then `then-form` is selected; otherwise `else-form` is selected. Whichever form is selected is then evaluated and its result value returns.\n\n**Example:**\n\n```common-lisp\n(let ((a 1))\n  (if (= a 1)\n      42\n      0))\n=\u003e 42\n```\n\n### [Syntax] let\n\n    LET ({(var value)}*) body =\u003e result\n\n`let` declares new variable bindings and set corresponding `value`s to them and evaluates `body` form that uses these bindings and returns its result. `let` performs the bindings in parallel. For sequentially, use `let*` kernel macro instead.\n\n**Example:**\n\n```common-lisp\n(let ((x 42))\n  x)\n=\u003e 42\n```\n\n### [Syntax] flet\n\n    FLET ({(name args local-form)}*) body =\u003e result\n\n`flet` defines locally named functions and evaluates its `body` with these definition bindings. Any number of such local functions can be defined. The scope of the name binding encompasses only the body. You may use built-in variables `i` and `n` in local functions as well as global kernel functions.\n\n**Example:**\n\n```common-lisp\n(flet ((aux (x) (+ x 1)))\n   (aux 10))\n=\u003e 11\n```\n\n### [Syntax] labels\n\n    LABELS ({(name args local-form)}*) body =\u003e result\n\n`labels` is equivalent to `flet` except that the scope of the defined function names for `labels` encompasses the function definition themselves as well as the body.\n\n**Examples:**\n\n```common-lisp\n(labels ((aux (x y)\n           (if (= x 0)\n               y\n               (aux (- x 1) (+ y 1)))))\n  (aux 10 0))\n=\u003e 10\n```\n\n### [Syntax] setf\n\n    SETF place value =\u003e result\n\n`setf` changes the value of `place` to be `value` and returns `value` as its result. Accessor forms are acceptable as `place`s.\n\n**Example:**\n\n```common-lisp\n(setf (aref xs i) (+ (aref xs i) (int2 1 1)))\n=\u003e (int2 1 1)\n```\n\n### [Built-in Function] int2, int3, int4\n\n    INT2 form form =\u003e result\n    INT3 form form form =\u003e result\n    INT4 form form form form =\u003e result\n\n`int2`, `int3` and `int4` provide constructors for `int` derived vector types. Each parameter form should have type of `int`.\n\n**Example:**\n\n```common-lisp\n(int2 0 0) =\u003e (int2 0 0)\n(int3 0 0 0) =\u003e (int3 0 0 0)\n(int4 0 0 0 0) =\u003e (int4 0 0 0 0)\n```\n\n### [Built-in Function] float2, float3, float4\n\n    FLOAT2 form form =\u003e result\n    FLOAT3 form form form =\u003e result\n    FLOAT4 form form form form =\u003e result\n\n`float2`, `float3` and `flaot4` provide constructors for `float` derived vector types. Each parameter form should have type of `float`.\n\n**Example:**\n\n```common-lisp\n(float2 0.0 0.0) =\u003e (float2 0.0 0.0)\n(float3 0.0 0.0 0.0) =\u003e (float3 0.0 0.0 0.0)\n(float4 0.0 0.0 0.0 0.0) =\u003e (float4 0.0 0.0 0.0 0.0)\n```\n\n### [Built-in Function] double2, double3, double4\n\n    DOUBLE2 form form =\u003e result\n    DOUBLE3 form form form =\u003e result\n    DOUBLE4 form form form form =\u003e result\n\n`double2`, `double3` and `double4` provide constructors for `double` derived vector types. Each parameter form should have type of `double`.\n\n**Example:**\n\n```common-lisp\n(double2 0.0d0 0.0d0) =\u003e (double2 0.0d0 0.0d0)\n(double3 0.0d0 0.0d0 0.0d0) =\u003e (double3 0.0d0 0.0d0 0.0d0)\n(double4 0.0d0 0.0d0 0.0d0 0.0d0) =\u003e (double4 0.0d0 0.0d0 0.0d0 0.0d0)\n```\n\n### [Accessor] int2-x, int2-y, int3-x, int3-y, int3-z, int4-x, int4-y, int4-z, int4-w\n\n    INT2-X form =\u003e result\n    INT2-Y form =\u003e result\n    INT3-X form =\u003e result\n    INT3-Y form =\u003e result\n    INT3-Z form =\u003e result\n    INT4-X form =\u003e result\n    INT4-Y form =\u003e result\n    INT4-Z form =\u003e result\n    INT4-W form =\u003e result\n\nAccesses each component of `int` derived vector types. The type of `form` should be of each accessor's corresponding vector type. The type of result is `int`. You can read its value as well as destructively set it with SETF form.\n\n**Example:**\n\n```common-lisp\n(int2-x (int2 1 2)) =\u003e 1\n(let ((x (int2 1 2)))\n  (setf (int2-x x) 3)\n  x)\n=\u003e (int2 3 2)\n```\n\n### [Accessor] float2-x, float2-y, float3-x, float3-y, float3-z, float4-x, float4-y, float4-z, float4-w\n\n    FLOAT2-X form =\u003e result\n    FLOAT2-Y form =\u003e result\n    FLOAT3-X form =\u003e result\n    FLOAT3-Y form =\u003e result\n    FLOAT3-Z form =\u003e result\n    FLOAT4-X form =\u003e result\n    FLOAT4-Y form =\u003e result\n    FLOAT4-Z form =\u003e result\n    FLOAT4-W form =\u003e result\n\nAccesses each component of `float` derived vector types. The type of `form` should be of each accessor's corresponding vector type. The type of result is `float`. You can read its value as well as destructively set it with SETF form.\n\n**Example:**\n\n```common-lisp\n(float2-x (float2 1.0 2.0)) =\u003e 1.0\n(let ((x (float2 1.0 2.0)))\n  (setf (float2-x x) 3.0)\n  x)\n=\u003e (float2 3.0 2.0)\n```\n\n### [Accessor] double2-x, double2-y, double3-x, double3-y, double3-z, double4-x, double4-y, double4-z, double4-w\n\n    DOUBLE2-X form =\u003e result\n    DOUBLE2-Y form =\u003e result\n    DOUBLE3-X form =\u003e result\n    DOUBLE3-Y form =\u003e result\n    DOUBLE3-Z form =\u003e result\n    DOUBLE4-X form =\u003e result\n    DOUBLE4-Y form =\u003e result\n    DOUBLE4-Z form =\u003e result\n    DOUBLE4-W form =\u003e result\n\nAccesses each component of `double` derived vector types. The type of `form` should be of each accessor's corresponding vector type. The type of result is `double`. You can read its value as well as destructively set it with SETF form.\n\n**Example:**\n\n```common-lisp\n(double2-x (double2 1.0d0 2.0d0)) =\u003e 1.0d0\n(let ((x (double2 1.0d0 2.0d0)))\n  (setf (double2-x x) 3.0d0)\n  x)\n=\u003e (double2 3.0d0 2.0d0)\n```\n\n### [Accessor] aref\n\n    AREF array index =\u003e result\n\nAccesses the `array` element specified by the `index`. The type of `array` is an array type with base type of `int`, `float`, `double` and their derived vector types. The type of `index` is `int`, and the type of `result` is the base type. You can read its value as well as destructively set it with SETF form.\n\n**Example:**\n\n```common-lisp\n(aref xs 0) =\u003e 1\n(setf (aref xs 0) 1) =\u003e 1\n(aref ys 0) =\u003e (int2 1 1)\n(setf (aref ys 0) (int2 2 2)) =\u003e 2\n```\n\n### [Built-in Variable] i, n\n\n`i` has the index of current AVM thread, `n` has the number of all AVM threads in a calling AVM kernel function. The both have type of `int`. You may use them in any kernel functions including ones called by another.\n\n**Examples:**\n\n```common-lisp\n(defkernel fill-zeros (xs)\n  (set (aref xs i) 0))\n```\n\n### [Built-in Function] +, -, *, /, mod\n\nThese functions provide arithmetic operations. `+` and `-` accept scalar type and vector type arithmetic. `*` and `/` accept scalar type arithmetic. `mod` accepts `int` type operands. `+`, `-`, `*` and `/` may take more than two arguments.\n\n```common-lisp\n(defkernel add2 (x y)\n  (the int2 (+ x y)))\n\n(defkernel add3 (x y z)\n  (the int2 (+ x y z)))\n```\n\n### [Built-in Function] \\*., .\\*, /., dot\n\nThese functions provide vector algebraic operations. `*.` scales a vector type value by a scalar type value. `.*` does the same thing,  letting a scalar value to scale a vector value. `/.` divides a vector type value by a scalar type value. `*.` and `/.` may take more than two arguments, repeatedly applying scalar values.\n\n```common-lisp\n(defkernel scale (x a b)\n  (the float3 (*. x a b)))              ; x is of float3 and a, b are of float\n\n(defkernel scaled (a x)\n  (the float3 (.* a x)))                ; a is of float and x is of float3\n```\n\n### [Built-in Function] \u003c, \u003e\n\nThese functions provide comparison operations for scalar type values.\n\n```common-lisp\n(defkernel one-or-two (a b)\n  (if (\u003c (the float a) b)\n      1\n      2))\n```\n\n### [Built-in Function] rsqrt\n\n    RSQRT x =\u003e result\n\nThese built-in functions provide mathematical functions.\n\n### [Built-in Macro] progn\n\n    PROGN\n\nTo be described.\n\n### [Built-in Macro] let*\n\n    LET*\n\nTo be described.\n\n## Concepts\n\n### Array\n\nThe array in AVM is an abstract data structure that consists of a memory area for computation on Lisp and another for computation on Nvidia CUDA.\n\n- Memory area for computation on Lisp\n  - Tuple array\n- Memory area for computation on CUDA\n  - Host memory\n  - Device memory\n\nEacn AVM thread of kernel functions reads from and writes to arrays. Arrays are passed to kernel fucntions on launching them.\n\n`alloc-array` allocates an array and it should be freed with `free-array`. For convenience, `with-array` macro and `with-arrays` macro are provided. `array-aref` accessor is used to read and write a value to an array. A value of arrays whose base type is a vector type is accessed via values.\n\n### CUDA state\n\nAVM has the following three states relevant to CUDA:\n\n- Not Available\n- Available\n- Used\n\nAnd here shows CUDA state's transfer diagram:\n\n```\nWITH-CUDA (nil)               WITH-CUDA (N)\n    +-----+      +--------------------------------------+\n    |     |      |                                      |\n    |     |      |                    *use-cuda-p* nil  |\n    |     |      |                     \u003c-------------   v\n    +-\u003e Not Available        Available                Used\n                                       -------------\u003e\n                                    *use-cuda-p* not nil\n```\n\nThe initial state is \"Not Available\". When CUDA state is \"Not Available\", AVM does not use CUDA. When AVM has this state is that actually CUDA is not available on your machine, out of `with-cuda` context or in `with-cuda` context with its `dev-id` parameter `nil`.\n\nWhen CUDA state is \"Available\", AVM is ready to use CUDA with initializing it and creating CUDA context as well as allocating device memory on `alloc-array`ing, though kernel functions are actually not executed on CUDA in this state. When AVM has this state is that CUDA is available on your machine within `with-cuda` context with its `dev-id` parameter an integer that indicates which GPU you use and `*use-cuda-p*` special variable is set to `nil`.\n\nWhen CUDA state is \"Used\", AVM is ready to use CUDA as well as when CUDA state is \"Available\" and kernel functions are actually executed on CUDA. When AVM has this state is same as when CUDA state is \"Available\" except that `*use-cuda-p*` special variable is set to not `nil`, which is the default value of that in `with-cuda` context.\n\n### Array states\n\nAVM's arrays have the following state variables:\n\n- CUDA availability\n- CUDA availability on allocation\n- Freed or not\n\nCUDA availability is if CUDA is available or not when array operations are called. CUDA availability on allocation is if CUDA was available or not when arrays are `alloc-array`ed. Free or not is if arrays are already `free-array`ed or not.\n\nHow array operations work is dependent of these state variables. For detail, see each array operation's API description.\n\n### Multi-threding state\n\nTo be described.\n\n## Author\n\n* Masayuki Takagi (kamonama@gmail.com)\n\n## Copyright\n\nCopyright (c) 2016 Masayuki Takagi (kamonama@gmail.com)\n\n## License\n\nLicensed under the MIT License.\n","funding_links":[],"categories":["Interfaces to other package managers"],"sub_categories":["Third-party APIs"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftakagi%2Favm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftakagi%2Favm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftakagi%2Favm/lists"}