Global variables are accessible by all functions loaded within a document(or drawing).
Local variables retain their value only as long as the function that defined them is running. After the function finishes running, the local variable values are automatically discarded, and the system reclaims the memory space the variable used.
Using Local Variable in the Program
1 2 3 4 5 6 7 8 9
(defun gp:getPointInput (/ StartPt EndPt HalfWidth) (if (setq StartPt (getpoint"\nStart point of path: ")) (if (setq EndPt (getpoint StartPt "\nEndpoint of path: ")) (if (setq HalfWidth (getdist EndPt "\nhalf-width of path: ")) T ) ) ) )
The local variables are declared following the slash character.
ActiveX® and Reactor functions of AutoLISP are demonstrated, as well as several other extensions to the AutoLISP language provided with Visual LISP.
There are two possible executino contexts for this tutorial:
The application may be run as interpreted LISP in piecemeal files and/ or functions that are loaded into a single document.
Or, the program code can be compiled into a VLX application, denoted by a *.vlx executable. A VLX operates from a self-contained namespace that can interact with the application-loading document.
Lesson 1: Designing and Beginning the Program(Visual LISP IDE)
Given a start point, an endpoint, and a width, draw a rectilinear boundary. The boundary can be at any 2D orientation. There should be no limit on how large or small it can be.
Prompt the user for tile size and tile spacing values. The tiles are simple circles and will fill the boundary but must not overlap or cross the boundary.
Place the tiles in alternating rows.
Example Location can be found in: C:\Program Files\Autodesk\AutoCAD 2022\Tutorial\VisualLISP
Getting Started With Visual LISP
First, it helps to demonstrate what can happen when Visual LISP is waiting for contorl to return from AutoCAD.
;;; Function C:GPath is the main program function and defines the ;;; AutoCAD GPATH command. (defun C:GPath () ;; Ask the user for input: first for path location and ;; direction, then for path parameters. Continue only if you have ;; valid input. (if (gp:getPointInput) ; (if (gp:getDialogInput) (progn ;; At this point, you have valid input from the user. ;; Draw the outline, storing the resulting polyline ;; "pointer" in the variable called PolylineName. (setq PolylineName (gp:drawOutline)) (princ"\nThe gp:drawOutline function returned <") (princ PolylineName) (princ">") (Alert"Congratulations - your program is complete!") ) (princ"\nFunction cancelled.") ) (princ"\nIncomplete information to draw a boundary.") ) (princ) ; exit quietly ) ;;; Display a message to let the user know the command name. (princ"\nType gpath to draw a garden path.") (princ)
defun: declare the funcation
C:GPath : Command, and the name is GPath
gp:getPointInput and getDialogInput: These function names are prefixed with gp: to indicate they are specific to the graden path applcation. This is not a requiremnet
The final princ without a string argument forces the program to exit quietly.
;;; Function gp:getPointInput will get path location and size (defun gp:getPointInput () (alert "Function gp:getPointInput will get user drawing input" ) ;; For now, return T, as if the function worked correctly. T ) ;;; Function gp:getDialogInput will get path parameters (defun gp:getDialogInput () (alert "Function gp:getDialogInput will get user choices through a dialog" ) ;;For now, return T, as if the function worked correctly. T ) ;;; Function gp:drawOutline will draw the path boundary (defun gp:drawOutline () (alert (strcat"This function will draw the outline of the polyline" "\nand return a polyline entity name/pointer." ) ) ;; For now, simply return a quoted symbol. Eventually, this ;; function will return an entity name or pointer. 'SomeEname )
The letter T is the symbol for “true” in AutoLISP
The way gpmain.lsp is structured, each input function it calls must return a value other than nil(no value) for the program to proceed to the next step.
An AutoLISP function will, by default, return the value of the last expression evaluated within it. In the stubbed-out functions, the only expression is a call to the alert function. But alert always returns nil. If this is left as the last expression in gp:getPointInput, it will always return nil, and you will never pass through the if to the gp:getDialogInput function.
For a similar reason, the end of the gp:DrawOutline function returns a quoted symbol (‘SomeEname) as a placeholder. A quoted symbol is a LISP construct that is not evaluated. (If you are curious about how the LISP language works, there are a number of good books available, mentioned at the end of this tutorial.)
AutoLISP is based on the LISP(LISt Processing) programming langauage.
A list is a structure enclosed by parentheses.
Usually, the first element in the list is the name of a function, and the following elements are called arguments.
1
(function_name [argument1 argumentX ...])
The ! (exclamation point) character can only be used at the AutoCAD Command prompt and is used to return the current value of an AutoLISP variable.
1
(+0.01 (*20.875))
2 * 0.875 = 1.75
0.01 + 1.75 = 1.76
1
(setq nDist (getreal"\nEnter a distance: "))
The getreal function prompts the user for a real numeric value. The value provided is then passed to the setq function and assigned to the nDist user-defined variable.
1
(alert (strcat"Welcome""to""AutoLISP!"))
The stract function combines all the strings into a single string value. The value returned bt the strcat function is then passed to the alert function and displayed in a message box.
Tutoiral: Creating a New Custom Command and Controllign wiht System Variables(AutoLISP)
Your custom commands can use standard AutoCAD commands with the command function, or they can directly manipulate objects using AutoLISP functions.
The defun function also allows you to define a list of arguments that can be passed to the function and a list of user-defined variable that are “local” to the function.
A custom command is a function that is defined with the defun function, but uses a special naming convention: they use the characters c: as a prefix. This distinguishes them from other functions.
You can define a function that accepts arguments, but you should never define a function that will be used as a custom command to accpet arguments.
1 2 3 4
(defun c:hello ( / msg) (setq msg (getstring T "\nEnter a message: ")) (alert msg) )
msg is a varible only exist inside the c:hello scope.
You can save your AutoLISP expressions to a file with the LSP file extension so they can be reused and loaded into other drawings.
Accessing and Setting System Variable Value
Getter/ Setter
getvar: Returns the current value of a system variable
setvar: Assigns a new value to a system variable
The following explain how to get and set the value of the OSMODE(Object Snap Mode) system varible.
At the Command prompt, enter (setq cur_osmode (getvar “osmode”)) The current value of the OSMODE system variable is returned and assigned to the user-defined variable of cur_osmode. While OSMODE returns an integer value, the value is the sum of multiple “bit-code“ values. For example, the value 35 indicates that the EndPoint(1), Midpoint(2) and Intersection(32) running object snaps are enabled.
At the Command prompt, enter osnap
Creating, Loading, and Opening an AutoLISP File(AutoLISP)
AutoLISP is an interpretive language, so it can be stored in an ASCII text file, loaded, and then executed directly within AutoCAD.
AutoLISP files typically have an .lsp file extension, but they can also have the .mnl file extension. Both LSP and MNL files can be edited with a text editor.
MNL files are associated with user interface customization and they are automatically loaded into AutoCAD when a customization (CUI/ CUIx) file of the same name is loaded. For example, the acad.mnl is automatically loaded into AutoCAD when the acad.cuix file is loaded.
We can open any text editor create and .lsp file and load it into AutoCAD.
The way to load it into AutoCAD.
Manage > Application> Load Application(Find the correct file)
Last Saturday, I hosted one weekly session for TokyoAEC. Mainly I talked about how we could develop the RevitAPI tools in Grasshopper. People who found it interested can take a look the link below:
There are usually some recommendation videos from MIT OCW on youtube for me. Shameless to say, although I am interested in the courses, I never finished any whole semester. But, Nah. I just want to note down those I clicked and gain some knowledge after all.
Premature optimization is the root of all evil. - Donald Knuth
More computing sins are committed in the name of efficiency(without necessarily achieving it) than for any other single reason - including blind stupidity -William Wulf
The First Rule of Program Optimization: Don’t do it. The Second Rule of Program Optimization - For experts only: Don’t do it yet. - Michael Jaskson
Making code readable and Fast
Vendor Solution: Multicore
Clock rate seem stop growing after around 2004.
To scale performance, processor manufacturers put many processing cores on the microprocessor chip
Each generation of Moore’s Law potentially doubles the number of cores.
Performance Is No Longer Free
Moore’s Law continues to increase computer performance. But now that performance looks like big multicore processors with complex cache hierarchies, wide vector units, GPU’s, FGPA’s, etc
Generally, software must be adapted to utilize this hardware efficiently.
Same code writen in different language, Python, Java and C, for example
Interpreters are versatile, but slow
The interpreter reads, interprets, and preforms each program statement and updates the machine state.
Interpreters can easily support high-level programming features - such as dynamic code alteration - at the cost of performance
JIT compilation
JIT compilers can recover some of the performance lost by interpretation.
When code is first executed, it is interpreted.
The runtime system keeps track of how often the various pieces of code are executed.
Whenever some piece of code executes sufficiently frequently, it gets compiled to machine code in real time.
Future executions of that code use the more-efficient compiled version.
Performance of Differnent Order
Loop Order
1 2 3 4 5 6 7
for(int i = 0; i < n; i++){ for(int j = 0; j < n; j++){ for(int k = 0; k < n; k++){ c[i][j] += A[i][j] * B[k][j]; } } }
what if we change the order of the loops, let’s say,
1 2 3 4 5 6 7
for(int k = 0; k < n; k++){ for(int j = 0; j < n; j++){ for(int i = 0; i < n; i++){ c[i][j] += A[i][j] * B[k][j]; } } }
Does this cause any performance difference?
cache location
Hardware Caches
Each processor reads and writes main memory in contiguous blocks, called cache lines.
Previously accessed cache lines are stored in a small memory, called a cache, that sits near the processor
Cache hits: accesses to data in cache -> are fast
Cache misses: accesses to data not in cache -> are slow
We can measure the effect of different access patterns using the Cachegrind cache simulator
1
valgrind --tool=cachegrind ./mm
Compiler Optimization
Clang provides a collection of optimization switches. You can specify a switch to the compiler to ask it to optimize.
Parallel Loops
The cilk_for loop allows all iterations of the loop to execute in parallel.
Experimenting with Parallel Loops
Parallel i Loop
1 2 3 4 5 6 7
clik_for(int i = 0; i < n; ++i){ for(int k =0; k < n ;++k){ for(int j =0; j < n ;++j){ c[i][j] += A[i][j] * B[k][j]; } } }
Running time: 3.18s
Parallel j Loop
1 2 3 4 5 6 7
for(int i = 0; i < n; ++i){ for(int k =0; k < n ;++k){ cilk_for(int j =0; j < n ;++j){ c[i][j] += A[i][j] * B[k][j]; } } }
Running time: 531.71s
Parallel i and j loops
1 2 3 4 5 6 7
cilk_for(int i = 0; i < n; ++i){ for(int k =0; k < n ;++k){ cilk_for(int j =0; j < n ;++j){ c[i][j] += A[i][j] * B[k][j]; } } }
Running time: 10.64s
For some reason, we cannot parallel k to get the correct answer.
Rule of Thumb: Parallelize outer loops rather than inner loops.
Using parallel loops gets us almost 18x speedup on 18 cores! (Disclaimer: Not all code is so easy to parallelize effictively.)
Vector Hardware
Modern microprocessors incorporate vector hardware to process data in single-instruction stream, multiple data stream(SIMD) fashion
Compiler Vectorization
Clang/LLVM uses vector instructions automatically when compiling at optimization level -02 or higher.
Many machines don’t support the newest set of vector instructions, however, so the compiler uses vector instructions conservatively by default.
Vectorization Flags
Programmers can direct the compiler to use modern vector instructions using compiler flags such as the following:
mavx: Use Intel AVX vector instructions
mavx2: Use Intel AVX2 vector instructions
Version Implementation
Python
Java
C
+interchange loops
+optimization flags
Parallel loops
+tilling
Parallel divide-and-conquer
+compiler vectorization
+AVX intrinsics
Plus More Optimizations
We can apply several more insights and performance-engineering trick to make this code run faster, including:
Preprocessing
Matrix transposition
Data alignment
Memory-managemnet optimizations
A clever algorithm for the base case that uses AVX intrinsic instructions explicitly