| The Resource Counter | |
| The resource counter, declared at include/linux/res_counter.h, | |
| is supposed to facilitate the resource management by controllers | |
| by providing common stuff for accounting. | |
| This "stuff" includes the res_counter structure and routines | |
| to work with it. | |
| 1. Crucial parts of the res_counter structure | |
| a. unsigned long long usage | |
| The usage value shows the amount of a resource that is consumed | |
| by a group at a given time. The units of measurement should be | |
| determined by the controller that uses this counter. E.g. it can | |
| be bytes, items or any other unit the controller operates on. | |
| b. unsigned long long max_usage | |
| The maximal value of the usage over time. | |
| This value is useful when gathering statistical information about | |
| the particular group, as it shows the actual resource requirements | |
| for a particular group, not just some usage snapshot. | |
| c. unsigned long long limit | |
| The maximal allowed amount of resource to consume by the group. In | |
| case the group requests for more resources, so that the usage value | |
| would exceed the limit, the resource allocation is rejected (see | |
| the next section). | |
| d. unsigned long long failcnt | |
| The failcnt stands for "failures counter". This is the number of | |
| resource allocation attempts that failed. | |
| c. spinlock_t lock | |
| Protects changes of the above values. | |
| 2. Basic accounting routines | |
| a. void res_counter_init(struct res_counter *rc, | |
| struct res_counter *rc_parent) | |
| Initializes the resource counter. As usual, should be the first | |
| routine called for a new counter. | |
| The struct res_counter *parent can be used to define a hierarchical | |
| child -> parent relationship directly in the res_counter structure, | |
| NULL can be used to define no relationship. | |
| c. int res_counter_charge(struct res_counter *rc, unsigned long val, | |
| struct res_counter **limit_fail_at) | |
| When a resource is about to be allocated it has to be accounted | |
| with the appropriate resource counter (controller should determine | |
| which one to use on its own). This operation is called "charging". | |
| This is not very important which operation - resource allocation | |
| or charging - is performed first, but | |
| * if the allocation is performed first, this may create a | |
| temporary resource over-usage by the time resource counter is | |
| charged; | |
| * if the charging is performed first, then it should be uncharged | |
| on error path (if the one is called). | |
| If the charging fails and a hierarchical dependency exists, the | |
| limit_fail_at parameter is set to the particular res_counter element | |
| where the charging failed. | |
| d. int res_counter_charge_locked | |
| (struct res_counter *rc, unsigned long val) | |
| The same as res_counter_charge(), but it must not acquire/release the | |
| res_counter->lock internally (it must be called with res_counter->lock | |
| held). | |
| e. void res_counter_uncharge[_locked] | |
| (struct res_counter *rc, unsigned long val) | |
| When a resource is released (freed) it should be de-accounted | |
| from the resource counter it was accounted to. This is called | |
| "uncharging". | |
| The _locked routines imply that the res_counter->lock is taken. | |
| 2.1 Other accounting routines | |
| There are more routines that may help you with common needs, like | |
| checking whether the limit is reached or resetting the max_usage | |
| value. They are all declared in include/linux/res_counter.h. | |
| 3. Analyzing the resource counter registrations | |
| a. If the failcnt value constantly grows, this means that the counter's | |
| limit is too tight. Either the group is misbehaving and consumes too | |
| many resources, or the configuration is not suitable for the group | |
| and the limit should be increased. | |
| b. The max_usage value can be used to quickly tune the group. One may | |
| set the limits to maximal values and either load the container with | |
| a common pattern or leave one for a while. After this the max_usage | |
| value shows the amount of memory the container would require during | |
| its common activity. | |
| Setting the limit a bit above this value gives a pretty good | |
| configuration that works in most of the cases. | |
| c. If the max_usage is much less than the limit, but the failcnt value | |
| is growing, then the group tries to allocate a big chunk of resource | |
| at once. | |
| d. If the max_usage is much less than the limit, but the failcnt value | |
| is 0, then this group is given too high limit, that it does not | |
| require. It is better to lower the limit a bit leaving more resource | |
| for other groups. | |
| 4. Communication with the control groups subsystem (cgroups) | |
| All the resource controllers that are using cgroups and resource counters | |
| should provide files (in the cgroup filesystem) to work with the resource | |
| counter fields. They are recommended to adhere to the following rules: | |
| a. File names | |
| Field name File name | |
| --------------------------------------------------- | |
| usage usage_in_<unit_of_measurement> | |
| max_usage max_usage_in_<unit_of_measurement> | |
| limit limit_in_<unit_of_measurement> | |
| failcnt failcnt | |
| lock no file :) | |
| b. Reading from file should show the corresponding field value in the | |
| appropriate format. | |
| c. Writing to file | |
| Field Expected behavior | |
| ---------------------------------- | |
| usage prohibited | |
| max_usage reset to usage | |
| limit set the limit | |
| failcnt reset to zero | |
| 5. Usage example | |
| a. Declare a task group (take a look at cgroups subsystem for this) and | |
| fold a res_counter into it | |
| struct my_group { | |
| struct res_counter res; | |
| <other fields> | |
| } | |
| b. Put hooks in resource allocation/release paths | |
| int alloc_something(...) | |
| { | |
| if (res_counter_charge(res_counter_ptr, amount) < 0) | |
| return -ENOMEM; | |
| <allocate the resource and return to the caller> | |
| } | |
| void release_something(...) | |
| { | |
| res_counter_uncharge(res_counter_ptr, amount); | |
| <release the resource> | |
| } | |
| In order to keep the usage value self-consistent, both the | |
| "res_counter_ptr" and the "amount" in release_something() should be | |
| the same as they were in the alloc_something() when the releasing | |
| resource was allocated. | |
| c. Provide the way to read res_counter values and set them (the cgroups | |
| still can help with it). | |
| c. Compile and run :) |