HON95 2 년 전
부모
커밋
70172b2258
8개의 변경된 파일200개의 추가작업 그리고 41개의 파일을 삭제
  1. 3 2
      general/linux-general.md
  2. 4 2
      hpc/slurm.md
  3. 2 0
      index.md
  4. 48 24
      linux-server/applications.md
  5. 1 1
      pc/arch-i3.md
  6. 13 4
      se/clang-llvm.md
  7. 94 8
      se/cpp.md
  8. 35 0
      se/openmp.md

+ 3 - 2
general/linux-general.md

@@ -406,9 +406,10 @@ Using GPG (from package `gnupg2` on Debian).
     - The nice value is inherited by child processes (meaning forking processes maintains the nice value it started with).
     - Use `renice` to change the value.
     - Use `ionice` to set the I/O scheduler and scheduler-specific priority.
-- Stress test with stress-ng:
+- Stress test with stress/stress-ng (see [Computer Testing](../computer-testing/)):
     - Install (Debian): `apt install stress-ng`
-    - Stress CPU: `stress-ng -c $(nproc) -t $((10*60))` (use all CPU threads for 10 minutes)
+    - Install (Arch): `apt install stress`
+    - Stress CPU: `stress(-ng) -c $(nproc) -t $((10*60))` (use all CPU threads for 10 minutes)
 - Chroot into other Linux installation:
     1. (Note) Used to e.g. fix a broken install or reset a user password from a USB live ISO.
     1. Mount the root partition: `mount /dev/sda2 /mnt` (example)

+ 4 - 2
hpc/slurm.md

@@ -20,8 +20,10 @@ breadcrumbs:
 
 - Create a job (overview): Make a Slurm script, make it executable and submit it.
 - Using GPUs: See example Slurm-file, using `--gres=gpu[:<type>]:<n>`.
-- Submit batch/non-blocking job: `sbatch <slurm-file>`
-- Start interactive/blocking job: `srun <job options> [--pty] <bash|app>`
+- Submit batch job: `sbatch <slurm-file>`
+- Start interactive job: `srun <job options> [--pty] <bash|app>`
+- Create allocation (without connecting to it): `salloc <job options>`
+    - Use e.g. `srun --jobid=<id> --pty bash` to connect to it.
 - Cancel specific job: `scancel <jobid>`
 - Cancel set of jobs: `scancel [-t <state>] [-u <user>]`
 - Show job queue: `squeue [-u <user>] [-t <state>] [-p <partition>]`

+ 2 - 0
index.md

@@ -136,12 +136,14 @@ _(Alphabetically sorted, so the ordering might seem a bit strange.)_
 ## Software Engineering
 
 - [C/C++ Tools](/se/ccpp-tools/)
+- [Clang/LLVM](/se/clang-llvm/)
 - [C++](/se/cpp/)
 - [Data Stuff](/se/data/)
 - [Database Management Systems (DBMSes)](/se/dbmses/)
 - [GNU Compiler Collection (GCC)](/se/gcc/)
 - [CUDA](/se/go/)
 - [Licensing](/se/licensing/)
+- [OpenMP](/se/openmp/)
 - [Web Security](/se/web-security/)
 
 ## Services

+ 48 - 24
linux-server/applications.md

@@ -386,30 +386,28 @@ Note: I recommend [Chrony](#chrony) instead of ntpd. It's newer and by design mo
 1. Configure servers/pool in `/etc/ntp.conf`, with the `iburst` option.
 1. Test with `ntpq -pn` (it may take a minute to synchronize).
 
-## NUT
+## Network UPS Tools (NUT)
 
 ### Setup
 
-Instructions for both servers and clients. Exclusive steps are marked "(Server)" or "(Client)".
-
-Since SSL/TLS is not enabled by default for client-server communication, use only trusted networks for this communication.
+Instructions for both primary nodes (netserver mode) and secondary nodes (netclient mode). Exclusive steps are marked "(Primary)" or "(Secondary)".
 
 1. Install: `apt install nut`
     - The service will fail to start since NUT is not configured yet.
-1. Set the mode: Open `/etc/nut/nut.conf` and set `MODE=netserver` for server or `MODE=netclient` for client.
-1. (Server) Add the UPS(s): Open `/etc/nut/ups.conf` and add a declaration for all UPSes (see example below).
+1. Set the mode: Open `/etc/nut/nut.conf` and set `MODE=netserver` for primaries or `MODE=netclient` for secondaries.
+1. (Primary) Add the UPS(s): Open `/etc/nut/ups.conf` and add a declaration for all UPSes (see example below).
     - Try using the `usbhid-ups` driver if using USB. Otherwise, check the [hardware compatibility list](https://networkupstools.org/stable-hcl.html) to find the correct driver. If the exact model isn't there, try a similar one.
     - For `usbhid-ups`, see the example below and [usbhid-ups(8)](https://networkupstools.org/docs/man/usbhid-ups.html).
     - You *may* need to modify some udev rules, but probably not.
-1. (Server) Restart driver service: `systemctl restart nut-driver.service`
-1. (Server) Set up local and remote access: Open `/etc/nut/upsd.conf` and set `LISTEN ::`.
+1. (Primary) Restart driver service: `systemctl restart nut-driver.service`
+1. (Primary) Set up local and remote access: Open `/etc/nut/upsd.conf` and set `LISTEN ::`.
     - Alternatively add one or multiple `LISTEN` directives for only the endpoints you wish to listen on.
-1. (Server) Set up users: Open `/etc/nut/upsd.users` and add users (see example below).
+    - Note that anonymous users (local or remote) have read-only access to everything, so remember you probably want to firewall this port.
+1. (Primary) Set up users: Open `/etc/nut/upsd.users` and add users (see example below).
     - Each client should have a separate user.
-1. (Server) Restart the server service: `systemctl restart nut-server.service`
-1. (Client) **TODO:** Something about `nut-client.service`.
-1. Monitor the UPS: Open `/etc/nut/upsmon.conf` and add `MONITOR <ups>@<host>[:<port>] <ups-count> <user> <password> <master|slave>`.
-    - `ups-count` is typically `1`. If this system is not powered by the UPS but you want to monitor it without shutting down, set it to `0`.
+1. (Primary) Restart the server service: `systemctl restart nut-server.service`
+1. Monitor the UPS: Open `/etc/nut/upsmon.conf` and add `MONITOR <ups>@<host>[:<port>] <powervalue> <user> <password> <primary|secondary>`.
+    - `powervalue` is how many power supplies this system has which is supplied by the UPS. It's used to calculate how many supplies are allowed to go offline. For single-PSU systems, use `1.` For dual-PSU systems with both connected to this PSU, use `2`. If this system is not powered by the UPS but you want to monitor it without shutting down when it goes critical, set it to `0`.
 1. (Optional) Tweak upsmon:
     - Set `RBWARNTIME` (how often upsmon should complain about batteries needing replacement) to an appropriate value, e.g. 604800 (1 week).
 1. (Optional) Add a notify script to run for certain events:
@@ -417,26 +415,26 @@ Since SSL/TLS is not enabled by default for client-server communication, use onl
     - In `/etc/nut/upsmon.conf`, set the script to run using format `NOTIFYCMD /opt/scripts/nut-notify.sh`.
     - Create the executable script. See an example below for sending email (if Postfix is set up).
 1. Restart monitoring service: `systemctl restart nut-monitor.service`
-1. Check the log to make sure `nut-monitor` successfully connected to the server.
-    - Note that `upsc` does not use a server user or the monitoring service, so it's not very useful for debugging that.
+1. Check the logs to make sure `nut-monitor` successfully connected to the server.
+    - Note that `upsc` uses the driver directly, so it's not useful for debugging the server or monitoring services.
 1. Configure delays:
     1. Figure out how much time is needed to shut down the master and all slaves, with some buffer time.
     1. Set the remaining runtime and remaining battery charge for when the UPS should send the "battery low" event (requires admin login): `upsrw -s battery.runtime.low=<seconds> <ups>` and `upsrw -s battery.charge.low=<percent> <ups>`
         - This may not work on all UPSes, even if the values appear to be modifiable. This means you're probably stuck with the defaults.
+        - **TODO** This resets when the driver or UPS is restarted, right?
     1. Set the delay from when the master issues the shutdown command to the UPS, to when the UPS powers off; and the delay from when the UPS receives power again to when it should turn on power: For `usbhid-ups`, this is set using `offdelay` and `ondelay`. Otherwise, it's set using `ups.delay.shutdown` and `ups.delay.start`. The start delay must be greater than the stop delay.
         - The shutdown command is issued from the master after it's done waiting for itself and slaves and is shutting itself down. The shutdown delay may be useful to increase if there are slaves that take much longer than the master to shut down.
     1. Restart the affected NUT services.
-1. Simulate a power loss, which should power off all monitoring clients and then the UPS: `upsmon -c fsd`
-    - If the client machines are not given enough time to power off before the UPS powers off, you need to modify the shutdown delay settings in the UPS.
+1. Simulate a power loss, which should shutdown the secondaries, the primary and then the UPS after a delay: `upsmon -c fsd`
 
-Example USB UPS declaration for `usbhid-ups` (`/etc/nut/ups.conf`):
+Example `/etc/nut/ups.conf` (uding `usbhid-ups` driver):
 
 ```
 [alpha]
     desc = "PowerWalker VI 3000 RLE"
     # usbhid-ups should work for most UPSes with
     driver = usbhid-ups
-    # If you have multiple UPSes connected, see usbhid-ups(8) for more specifying which USB device it should use
+    # Required but ignored by this driver
     port = auto
     # Sets "ups.delay.shutdown", the delay between the shutdown command and when the UPS powers off (default 20s)
     offdelay = 60
@@ -444,17 +442,41 @@ Example USB UPS declaration for `usbhid-ups` (`/etc/nut/ups.conf`):
     ondelay = 120
 ```
 
-Example server users (`/etc/nut/upsd.users`):
+Example `/etc/nut/upsd.users`:
 
 ```
 [admin]
     password = <password>
-    actions = SET
-    instcmds = ALL
+    actions = set
+    actions = fsd
+    instcmds = all
+
+[upsmon_local]
+    password = <password>
+    upsmon primary
 
-[local]
+[upsmon_remote]
     password = <password>
-    upsmon master
+    upsmon secondary
+```
+
+Example `/etc/nut/upsmon.conf`:
+
+```
+MONITOR alpha@localhost:3493 1 upsmon_local password1234 primary
+MINSUPPLIES 1
+POLLFREQ 5
+POLLFREQALERT 5
+DEADTIME 20
+HOSTSYNC 20
+FINALDELAY 5
+POWERDOWNFLAG /etc/killpower
+NOTIFYCMD "/usr/bin/true"
+SHUTDOWNCMD "/sbin/shutdown -h +0"
+NOCOMMWARNTIME 3600
+RBWARNTIME 604800
+
+# See the original for NOTIFYMSG and NOTIFYFLAG examples.
 ```
 
 Example notify script:
@@ -471,6 +493,8 @@ echo -e "Time: $(date)\nMessage: $@" | mail -s "NUT: $@" root
 
 #### Query the Server
 
+Note: Anonymous users have read-only access to everything.
+
 1. Telnet into it: `telnet localhost 3493`
 1. Show UPSes: `LIST UPS`
 1. Show UPS vars: `LIST VAR <ups>`

+ 1 - 1
pc/arch-i3.md

@@ -161,7 +161,7 @@ Note: The use of `sudo` in the text below is a bit inconsistent, but you should
         1. In `/etc/iwd/main.conf`, in section `Scan`, set `DisablePeriodicScan=true`.
     1. Enable `iwd`: `sudo systemctl enable --now iwd.service`
         - **TODO** I think this renamed my WLAN interface. Make sure your systemd-network config is correct.
-    1. Install GUI: `yay -S iwgtk`
+    1. Install GUI: `yay -S iwgtk snixembed-git`
     1. Start the GUI tray icon: `iwgtk -i`
         - It should normally start automatically using XDG autostart.
         - **TODO** This doesn't currently work since the group is broken.

+ 13 - 4
se/clang-llvm.md

@@ -26,13 +26,22 @@ LLVM is an extensive compiler platform and toolchain. It's typically used as the
     - E.g. `-target x86_64-unknown-linux-gnu`.
     - This is generally needed only if cross-compiling, the default will be a target fitting the local computer.
     - Use `llc --version` to show supported platforms.
-- Specify target OpenMP GPU platform/arch: `-fopenmp -fopenmp-targets=<platform> -Xopenmp-targets=<platform> -march <arch>`
-    - Requires an LLVM-based compiler with proper OpenMP offloading support, like AMD ROCm's LLVM.
-    - E.g. `-fopenmp -target x86_64-pc-linux-gnu -fopenmp -fopenmp-targets=amdgcn-amd-amdhsa -Xopenmp-target=amdgcn-amd-amdhsa -march=gfx1030` (AMD RX 6800 XT).
-    - E.g. `-fopenmp -fopenmp-targets=nvptx64-nvidia-cuda -Xopenmp-target=nvptx64-nvidia-cuda -march=sm_60` (NVIDIA V100)
 
 ## Hardware Offloading
 
+### OpenMP Offloading
+
+- Specify target OpenMP GPU platform/arch: `-fopenmp -fopenmp-targets=<platform> -Xopenmp-targets=<platform> -march <arch>`
+    - Requires an LLVM-based compiler with proper OpenMP offloading support, like AMD ROCm's LLVM.
+    - E.g. `-fopenmp -fopenmp-targets=amdgcn-amd-amdhsa -Xopenmp-target=amdgcn-amd-amdhsa -march=gfx1030` (AMD RX 6800 XT).
+    - E.g. `-fopenmp -fopenmp-targets=nvptx64-nvidia-cuda -Xopenmp-target=nvptx64-nvidia-cuda -march=sm_70` (NVIDIA V100)
+- Emit optimization diagnostics during compilation:
+    - `-Rpass=...`: When a pass makes a transformation.
+    - `-Rpass-missed=...`: When a pass fails a transformation.
+    - `-Rpass-analysis=...`: More info about whether or not to make a transformation.
+    - The options take a regex to match which optimization pass to show (use `'.*'` to match all).
+- Show runtime debug info: `LIBOMPTARGET_INFO=1`
+
 ### NVIDIA GPUs (CUDA/NVPTX)
 
 - See: [LLVM: User Guide for NVPTX Back-end](https://llvm.org/docs/NVPTXUsage.html)

+ 94 - 8
se/cpp.md

@@ -33,6 +33,7 @@ breadcrumbs:
 - To use symbols from the global namespace, prefix with `::`.
 - To import all symbols from a namespace, specify `using namespace <namespace>`.
 - To import specific symbols from a namespace, specify `using <namespace>::<symbol>`.
+- Most C libraries are migrated into the `std` namespace, in header files with a `c` prepended and no `.h` extension (e.g. `math.h` becomes `cmath`).
 
 ### Functions
 
@@ -47,14 +48,16 @@ breadcrumbs:
 
 - One or more constructors may be declared using overloading.
 - Only one destructor may be declared (since it takes no arguments).
-- Use virtual destructors when using inheritance to avoid calling the wrong destructor.
+- The default constructor is the one constructor that takes no arguments and is implicitly created.
 - Default constructors are _usually_ called implicitly when leaving out the `()`, but if you want the object in a consistent state, you may want to explicitly specify it (e.g. `A a()`, `new A()`, `new A[n]()`), to avoid subtle cases where the default constructor is called but certain member variables are still left uninitialized. (See default and value initialization.)
 - **TODO** `= delete` and `= default`.
 - Constructors may use initializer lists to initialize member variables from constructor arguments. The initializer list is called before the constructor body.
-- After the destructor executed, the destructors for all direct member variables are called.
+- After the destructor has executed (for the specified type or the most-derived if virtual), the destructors for all direct member variables are called.
+- `delete` implicitly calls the destructor of a single object, `delete[]` for all objects in the array.
+- One-argument constructors may be used for inplicit conversion, such that e.g. `Balance b = 100` implicitly calls the `Balance(long value)` constructor. Use keyword `explicit` for the constructor declaration to deny implicit conversions (only valid for one-argument constructors).
 - See the rule of three/five below for more info about copy and move constructors.
 
-#### Visibility (aka Access Modifiers)
+#### Access Levels (aka Visibility)
 
 - For class/struct members (fields and functions), declared using `private:`/`public:`/`protected:` modifiers in the class declaration, applies to all members below it.
 - Modifiers:
@@ -66,8 +69,20 @@ breadcrumbs:
 
 #### Inheritance
 
-- **TODO**
-- Use virtual destructors to avoid calling the wrong destructor.
+- Derived classess (aka subclasses) inherit one or more base classes (aka superclasses), using syntax `class B : public A`.
+- Derived classes may inherit multiple base classes by specifying multiple (comma-separated) base classes (with individual access levels) in the class declaration. For duplicate inherited members, scopes must be specified in order to refer to the right version.
+- For cases of multiple inheritance where base classes derive the same base class higher in the inheritance hierarchy, base classses may be marked as virtual (called virtual base classes) derived class declarations to avoid getting duplicated members from the multiple inherited base class.
+- To control the access level of inherited members, specify `public`, `protected` or `private` in the inheritance part of the declaration (`class B : public/protected/private A`).
+    - `public` leaves inherited member access levels unchanged.
+    - `protected` makes inherited public members protected.
+    - `private` makes all inherited members private.
+- Use virtual member functions (`virtual`) to use polymorphism (aka dynamic bindings), in order to override member functions of base classes. Not marking the member as virtual will instead call the member function of the current class the instantiated class is assigned to, which may cause unexpected behavior. When a member function is marked at some point in the derivation chain, it is virtual from that point regardless of whether derived classes mark it as such too, but it's useful for documentation purposed to mark it in derived classes too.
+- Use virtual destructors to avoid breaking the polymorphism and potentially cause memory leaks.
+- For construction, the most base class is constructed first. The default constructors of base classes are implicitly called. To call a specific non-default constructor of the base class, specify it as the first element in the initialization list (`sub_class(...) : super_class(...) {}`).
+- For destruction, the most derived class is destructed first.
+- Member functions may be purely virtual by specifying both `virtual` and `= 0` in the declaration, meaning any concrete, derived classes need to implement it. A class with any pure virtual member functions is called an abstract class since it can't be instantiated. (Although, a definition of the pure virtual member function may actually be provided for the same class that declares it as pure virtual. Destructors may also be declared as pure virtual, but need an implementation in the same class.)
+- Keep in mind that the use of virtual mechanisms (aka dynamic bindings) may reduce performance as it incurs a required lookup at run-time.
+- Remember to pass-by-reference to avoid implicit copying and breaking polymorphism.
 
 ### Enums
 
@@ -75,16 +90,78 @@ breadcrumbs:
 
 ### Strings
 
-- (New with C++) `string` is generally used instead of raw `char *`, which is more sophisticated and handles its own resource usage.
+- `string` is generally used instead of raw `char *` as in C, which is more sophisticated and handles its own resource usage.
+- Raw string literals may be used to avoid interpreting escape sequences and quotation marks, e.g. `R"--(File("yolo")\n)--"` contains string `File("yolo")\n` (the `--` part used here is optional and may be anything).
+
+### Streams
+
+- For writing to STDOUT/STDERR and reading from STDIN, C++ uses the `cout`/`cerr`/`clog` and `cin` streams from the `iostream` library, unlike C which uses `print` variants (`clog` is the buffered version of `cerr`).
+- To set `cout` to print floating-point numbers as fixed-precision, set `cout.setf(ios::fixed)` and `cout.precision(3)` (for 3 decimals).
 
 ### Arrays and Containers
 
-- (New with C++) `array` (static), `vector` (dynamic), `map` (dynamic) etc. instead of raw arrays (`A a[]` or `A *a`).
+- Containers like `array` (static), `vector` (dynamic), `map` (dynamic) etc. are recommended instead of raw arrays as in C (`A a[]` or `A *a`).
 - Using `new A[n]` will default-initialize the elements, meaning classes will have their default constructor called but primitive types will not get assigned any value (i.e. they may contain garbage data after initialization). To null-initialize an array of primitives, use `new A[]()` instead (has no effect for class/struct types).
+- `vector`:
+    - It has a capacity and a size. Use `.reserve(n)` to change the capacity (same as size or larger) and `.resize(n)` to change the size (create new elements or drop the tail).
+
+### Templates
+
+- Classes and functions may be templated with type (`class/typename T`) and non-type (e.g. `int t`) arguments in order to generate multiple variants at compile-time. Instantiations of them for specific types are called specializations of the template.
+- Templated classes/functions are preceded by e.g. `template <class T>`. If multiple types are required, comma-separate them.
+- `class` and `typename` are generally interchangable, but there are some special cases where only one is appropriate (e.g. dependent types).
+- Non-type arguments must be constant. They're useful e.g. to allocate storage for a specified number of elements (tuples and constant-length arrays).
+- Explicit specialization is typically used for overloading classes/functions for specific types. It uses `template <>` (no types here), then e.g. `<double>` (the type to overload for) after the class/function name.
 
 ### Exceptions
 
 - (New in C++) Supports exceptions (for better or worse).
+- Typical `try/catch(Exception &ex)` and `throw ex` syntax. `catch(...)` is used as catch-all.
+- For multiple `catch` clauses, the first one to match is used. If no clauses match, it's thrown further up the stack.
+- Standard exceptions are derived from the `exception` class from library `exception`. It has a `what()` function to get its name.
+- Receive exceptions by reference to avoid breaking polymorphism.
+- Exception specifications:
+    - Used to guarantee which exceptions a function may throw.
+    - Specified as `throw(ExceptionA, ExceptionB)` after the function signature (both in the declaration and definition).
+    - An empty list means that it can't throw any exceptions.
+    - No specification means that it can throw any exception.
+    - An overridden member function in a derived class must be at least as restructive as in the base class.
+    - If it throws an exception not specified in the list, the standard function `unexpected` is called, which terminates the program by default.
+- Examples:
+    - Use `new(nothrow) ...` to return a null-pointer instead of throwing a `bad_cast` exception if the allocation fails.
+
+### Operator Overloading
+
+- A function `operatorX` for some unary or binary operator `X` (e.g. `<<` or `+`). May be part of a class, where the implicit parameter becomes the first argument.
+- The associativity, precedence and arity of the operator can't be changed.
+- The `()` operator may be overloaded to create function objects.
+- The `new/new[]/delete/delete[]` operators (including placement new) may also be overloaded in order to implement custom resource management.
+- Examples:
+    - Used for I/O streams to print stuff with `<<`.
+    - Used by classes to implement/override the copy and move assignment operators.
+
+### Casts
+
+- C-style casting (e.g. `(int) 1.0`) is allowed but not recommended. No checks are performed so usage is unsafe.
+- C++-style casts look like `int b = static_cast<int>(a)` (bad example).
+- `dynamic_cast<>()`:
+    - Used to cast objects between derived classes of some shared base class, either by upcasting, downcasting or crosscasting. The class must (?) be polymorphic, i.e. using virtual functions.
+    - Runtime type information must be turned on for it to work properly, although the compiler catches whichever errors it can.
+    - For illegal casts with pointer types, it returns a null-pointer. For reference types, it throws an exception.
+- `static_cast<>()`:
+    - Like `dynamic_cast`, but without the runtime checks so it can cast between non-polymorphic types etc. It's more similar to C-style casts.
+- `const_cast<>()`:
+    - Used to cast away `const` and/or `volatile`.
+    - Considered safe only if the data was initially declared without `const`/`volatile`.
+- `reinterpret_cast<>()`:
+    - Used to cast between any pointer types, including to/from integral types.
+    - Typically only used for byte-level data fuckery.
+- About runtime type informatin (RTTI):
+    - RTTI may not be embedded by default, since C++ is a statically typed language and doesn't need it during runtime (with significant exceptions).
+    - `typeid()` returns type info about a value, in the form of a `type_info`. The `typeinfo` header is required to use it.
+    - For polymorphic types, `typeid()` returns the dynamic type.
+    - `type_info` overloads `==` and `!=` in order to easily compare types.
+    - `type_info` contains a `name()` method to get the name of the type.
 
 ### Miscellanea
 
@@ -93,6 +170,12 @@ breadcrumbs:
 
 ## Mechanisms and Idioms
 
+### Asserts
+
+- Asserts may be used to implement pre-conditions and post-conditions when deloping applications.
+- Asserts can be disabled when building for release by setting `#define NDEBUG` (before the `cassert` import) or by specifying `-DNDEBUG` for GCC.
+- Include `cassert` to use macro `void assert(bool)`.
+
 ### Resource Acquisition is Initialization (RAII)
 
 - RAII is a way to tie a resource held by an object to the objects lifetime, thus automatically allocating the resource when the object is constructed and automatically deallocating the resource when the object is destructed.
@@ -100,7 +183,7 @@ breadcrumbs:
 - Examples:
     - `string` and `vector` manages their own resources (no manual `new[]` or `delete[]`).
     - `unique_ptr` and `shared_ptr` makes it simpler to manage heap-allocated elements, including C-style arrays.
-    - `std::lock_guard<mutex>` makes automatically locks the mutex and automatically releases it when deallocated (e.g. when returning from the function).
+    - `std::lock_guard<mutex>` automatically locks the mutex when created and automatically releases it when deallocated (e.g. when returning from the function).
 
 ### Argument-dependent lookup (ADL)
 
@@ -114,6 +197,7 @@ breadcrumbs:
 - The rule of three denotes that if you need to explicitly declare either the destructor, copy constructor or copy assignment operator, you probably need to explicitly declare all of them.
 - The rule of five extends the rule of three with the move constructor and move assignment operator (introduced in C++11).
 - For simple classes with no resources to manage directly, the rule of zero is typically good enough (no special member functions).
+- For polymorphic classes, it may be an appropriate idea to implement a virtual `clone()` function instead of a the copy constructor.
 
 #### Copy Semantics
 
@@ -151,6 +235,8 @@ breadcrumbs:
 
 ### Miscellanea
 
+- Don't rely on default-initialization, the rules are really clunky (some things are zero-initialized, some things are not initialized at all).
 - Don't specify `using namespace std`, keep the `std::` specifiers.
+- Never use `wchar_t` or `wstring` (e.g. for UTF-16) unless you have to (e.g. for library calls), use regular `char` and `string` (e.g. for UTF-8).
 
 {% include footer.md %}

+ 35 - 0
se/openmp.md

@@ -0,0 +1,35 @@
+---
+title: OpenMP
+breadcrumbs:
+- title: Software Engineering
+---
+{% include header.md %}
+
+## General
+
+- Use `default(firstprivate)`. The "default default" is `shared`, which may be inefficient, whereas `firstprivate` copies the initial value and then uses a local variable instead.
+
+## Target Offloading
+
+- **TODO** `target/device/teams/distribute/etc`
+- Declare/define target function: Add `#pragma omp begin declare target` before and `#pragma omp end declare target` after. It can now be used by both host and target.
+- Try to avoid using library math functions as they may contain a lot of CPU-specific code like AVX-instructions which won't work in offloaded regions.
+- The host waits for target regions to finish. To run it asynchronously instead (as a task), specify `nowait`.
+- `depend(in/out: <var>)` may be used to declare variable dependencies for regions, mainly for use with tasks and `nowait` target regions.
+- Run region with a set number of teams (aka blocks in CUDA) and threads:
+    ```c
+    // CUDA-equivalent: compute_stucc<<<1, 4>>>(args)
+    #pragma omp target teams num_teams(1)
+    {
+        before_stuff();
+        #pragma omp parallel num_threads(4) default(firstprivate)
+        {
+            compute_stuff(args);
+        }
+        after_stuff();
+    }
+    ```
+- Use `#pragma omp target update ...` to update variables to/from device.
+- `#pragma omp barrier` works inside target blocks too.
+
+{% include footer.md %}