The goal of this task is to provide feedback on the initial API design of another team. To this end, you have been provided with a new repository (in the task-3 project group) containing a snapshot of another team’s repository.

The task has two parts: the first part is intended to let you try out the provided API (by creating an example application) and the second part is a review of the library and its API. The review consists of several paragraphs of coherent text (not a bullet list).

Good reviews have somewhere between 800–1000 words (excluding source code examples). Some very nice had around 2000 words, but it is also possible to write bad review in 2500 words or more.

This task is done individually so that each team (including yours) receives feedback from two other students.

Part 1: example application

Use the provided API to implement a skeleton of the numactl command (see man page for details) and integrate it into the project as another example in addition to the example that should already be present. Pay attention to how the library contributed (or failed to contribute) to this task.

Keep in mind that the purpose of the task is to learn the API and use it to write the argument-parsing part of the program, not implementing numactl features. Your skeleton application is therefore expected to say what it would be doing, not actually do it, just like in the following example:

args = ... // configure the arguments
args.parse(argv)
if args.has("--show"):
   print("policy: default"); print("...")
elif args.has("--hardware"):
   print("available: 2 nodes (0-1)"); print("...")
elif:
   print("will run %s" % args.get_command())
   print("CPU node bind: %s" % args.get("-C").join(","))
   ...

Your numactl skeleton must support the following invocation styles:

  • Without any parameters, the program should print help.
  • Given the --hardware switch, it should emulate printing the current hardware configuration.
  • Given the --show switch, it should emulate printing the current NUMA policy.
  • Given options -m, -p, -i, and -C, it should emulate running another program with the modified NUMA policy.

See below for details on the individual invocation styles.

Displaying help text

numactl

When run without any arguments, the command should print help text that summarizes the supported options, switches, commands, i.e., something along these lines:

usage: numactl [--interleave= | -i <nodes>] [--preferred= | -p <node>]
               [--physcpubind= | -C <cpus>] [--membind= | -m <nodes>]
               command args ...
       numactl [--show | -s]
       numactl [--hardware | -H]

<nodes> is a comma delimited list of node numbers or A-B ranges or all.
<cpus> is a comma delimited list of cpu numbers or A-B ranges or all.

--interleave, -i   Interleave memory allocation across given nodes.
--preferred, -p    Prefer memory allocations from given node.
--membind, -m      Allocate memory from given nodes only.
--physcpubind, -C  Run on given CPUs only.
--show, -S         Show current NUMA policy.
--hardware, -H     Print hardware configuration.

Ideally, this text (or most of it) would be generated by the library based on the defined options and their description.

Displaying hardware configuration

numactl --hardware

When run with the --hardware switch (or its short alias -H), the command prints the system hardware configuration:

available: 2 nodes (0-1)
node 0 cpus: 0 2 4 6 8 10 12 14 16 18 20 22
node 0 size: 24189 MB
node 0 free: 18796 MB
node 1 cpus: 1 3 5 7 9 11 13 15 17 19 21 23
node 1 size: 24088 MB
node 1 free: 16810 MB
node distances:
node   0   1
  0:  10  20
  1:  20  10

Displaying current configuration

numactl --show

When run with the --show switch (or its short alias -s), the command prints the current configuration (policy):

policy: default
preferred node: current
physcpubind: 0 1 2 3 4 5 6 7 8
cpubind: 0 1
nodebind: 0 1
membind: 0 1

Running programs with a specific NUMA policy

numactl [policy-configuration-for-command] command args ...

Without the --hardware or --show options, the numactl utility allows running other programs under a given NUMA policy. Your skeleton implementation does not have to run any commands, but it needs to print the final policy used to run command with args.

  • --physcpubind|-C accepts list of CPUs (range 0-31)
  • --membind|-m accepts list of NUMA nodes (range 0-3)
  • --preferred|-p accepts single NUMA node (0-3)
  • --interleave|-i accepts list of NUMA nodes (range 0-3)
  • options -m, -p and -i are conflicting and only one can be present
  • command cannot be empty, args are optional

Note that -C, -m, -i are actually lists of integers that are created from either of the following forms:

  • all
  • 1,3,8,2
  • 1-5,8,10-17

Part 2: review

The purpose of the review is to provide the library authors with written feedback on the initial design of their library API.

Your feedback is not going to cost the other team any points, so you are encouraged to provide an honest opinion while keeping your tone civil. Strive to provide constructive criticism, i.e., support your opinions with examples and provide suggestions on what to improve and how. In this regard, prefer quality over quantity, i.e., focus on a few well-argued points targeting the most important issues, instead of tearing the solution apart in a flurry of details without much depth.

Also keep in mind that reviewing does not mean that you are only expected to criticize — don’t be afraid to praise where you believe it is due.

Your review should adhere to the following (rough) outline:

  • First impression

    Summarize your first impression of the library project after cloning it.

    People usually expect README.md to contain basic information about a project, so a good README.md can go a long way in setting up the user’s expectations by answering some of the potential questions up front:

    • What does the project/library do?
    • What are the key concepts (and where can I learn more)?
    • How to use the library (short tutorial or a simple example)?
    • Can the library be extended (more complex example)?
    • Which use cases can it cover (and which are beyond its scope)?
    • How to build the library/documentation (and what is needed for that)?

    Keep in mind that this is an initial version, so not everything might be completely fleshed out, but you should not have trouble getting the library to compile or integrating your example program into the project.

  • API review

    Summarize the basic concepts provided by the library. In this section, you should avoid discussing low-level technical details. Instead, you should discuss the API style, the responsibilities assumed by the library and those expected from the user.

    Consider common situations in which the library API is going to be used (i.e., parser definition, parsing the command line, access to parsed values, and error handling) and comment on the comfort of using the API in these situations.

    Check the API documentation to see if it is clear what the API methods expect from the developer and how they should behave. Also find out what the library can/cannot do in the context of the task-1 requirements, i.e., how does it satisfy the functional requirements and if deviations are documented/justified.

  • Writing numactl

    Describe your experience implementing the argument-processing part of the numactl command. Comment on how the concepts required to implement the example match the concepts offered by the library. Point out what was easy (conceptual match), difficult (conceptual mismatch but workaround possible), or impossible to implement with the help of the library.

  • Detailed comments

    Provide detailed comments on specific issues (or highlights). In this section, you will typically discuss technical details and refer to specific classes and interfaces rather than high-level concepts.

    See the checklist below for potential questions that you can be asking yourself about the library. The list is not exhaustive and you are not required to answer all those questions in your review — the purpose of the checklist is to aid in systematic API exploration (or if you are stuck and wonder what to write about).

Review checklist

  • Library API

    • How does the user define parsable elements and their properties?
    • Are bounded integers, enums and strings parameter types supported?
    • Can the library generate help text based on user-provided documentation?
    • Is it possible to parse and/or validate custom parameter types and how?
    • What happens when and error (due to programmer or CLI user) occurs?
    • What is needed (information, steps) to access the parsed values?
    • Who is responsible for storing the parsed data and where?
    • Is the API declarative or imperative, stateful or stateless?
    • Does the API use mutable or immutable objects?
    • Can a user define multiple independent parsers? Is there any global state?
    • Is the API consistent? Can it be used in the wrong way?
    • Does the naming fit the problem domain?
    • Is the client code easy to read?
    • … and many others …
  • External documentation

    • What are the goals and non-goals of the library?
    • What are the key concepts provided by the library?
    • What are the key design decisions and how they reflect the library goals?
  • Source code documentation

    • Are all public classes documented?

      What is the responsibility of the class and how does it fit among the other concepts provided by the library?

    • Are all public methods documented?

      Is it clear what each method does, and how does it react to invalid data or invalid usage by the programmer, such as invalid parameter values? What constitutes valid and invalid parameter values?

    • Was the example program documented?

    • Was the documentation good enough for writing numactl or not?

  • Code style

    • Does the code follow platform conventions (naming etc.)?
    • Is the source code formatting consistent?

Submission

To submit your solution to this task, commit both the numactl example and the review to the master branch of the provided repository, and tag the final commit using the task-3-submission tag.

  • The numactl example should be integrated (in a reasonable way) into the library project, ideally as a separate sub-project.

  • The review must be a markdown document named REVIEW.md (case sensitive) placed in the .nprg043 directory, i.e., the path to the file from the project root should be .nprg043/REVIEW.md.

    Please note that submissions that fail to place the review file in the required location (or use a different name) will receive a penalty of 1 point, because handling such submissions requires manual intervention.