Issue
Building off of this, I would like to change process priorities based on RAM usage. I'm perfectly aware that this isn't always the best way to change priorities, but this is just for a project. I'm trying to use renice and execvp to set process priorities.
The problem is that I want to launch renice with additional parameters to change the process priority while the program is running. The problem is that when I run execvp with the correct #include it bounces an error with a lot of dependencies.
My main.c has two arrays. One has the process IDs and the other has their corresponding RAM usage and they get sorted in descending order. Is there any way to change process priorities with this information?
main.c
#include </usr/include/asm-generic/unistd.h> //execvp:
#include <linux/kernel.h> // printk(), pr_*()
#include <linux/module.h> // THIS_MODULE, MODULE_VERSION, ...
#include <linux/init.h> // module_{init,exit}
#include <linux/sched/task.h> // struct task_struct, {get,put}_task_struct()
#include <linux/mm.h> // get_mm_rss()
#include <linux/pid.h> // struct pid, get_pid_task(), find_get_pid()
#include <linux/moduleparam.h> // module_param_named()
#include <linux/slab.h>
struct task_struct *task; /* Structure defined in sched.h for tasks/processes */
/*
* Power Services: 80-51%
* renice -n 5 -p [pid] //(20-5)/20 = 75% of CPU
* Standard Services: 50-26%
* renice -n 10 -p [pid] //(20-10)/20 = 50% of CPU
* Optimized Services: 1-25%
* renice -n 15 -p [pid] //(20-15)/20 = 25% of CPU
*/
/*
static char *envp[] = {
"SHELL=/bin/bash",
"HOME=/bin/admin0",
"USER=admin",
"PATH=/home/admin/bin:/home/admin/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/home/admin",
"DISPLAY=:0",
"PWD=/home/admin",
NULL};
*/
typedef struct
{
int *array;
size_t used;
size_t size;
} id_array;
typedef struct
{
unsigned long *array;
size_t used;
size_t size;
} ram_array;
int rss = 0;
int counter = 0;//Iterator for arrays
//Change according to available memory size
int highLimit =322122547; //3GB
int mediumLimit=214748364;//2GB
int lowLimit= 107374182;//1GB
//The RAM usage and process ID data types are different and require different argument types
void initArray(id_array *a, size_t initialSize);
void insertArray(id_array *a, int element);
void initarray(ram_array *a, size_t initialSize);
void insertarray(ram_array *a, long unsigned element);
// Function to swap the the position of two elements
void swapper(long unsigned *a, long unsigned *b);
void id_swap(int *a, int *b);//Swap IDs when sorting
void heapify(unsigned long* arr, int n, int i, int *id);
// Main function to do heap sort
void heapSort(ram_array *a, id_array *b);
id_array pid;
ram_array ram;
int iterate_init(void) /* Init Module */
{
printk(KERN_INFO "%s","LOADING MODULE\n"); /* good practice to log when loading/removing modules */
initArray(&pid, 1);
initarray(&ram, 1);
for_each_process( task ) //Loop through all the processes to count how many there are. This function is located in linux\sched\signal.h
{
get_task_struct(task);
insertArray(&pid, task->pid);
if(task->mm)
{
rss = get_mm_rss(task->mm) << PAGE_SHIFT;
insertarray(&ram, rss);
}
else
{
insertarray(&ram, 0);
}
counter++;
put_task_struct(task);
}
counter = 0;
heapSort(&ram, &pid);
while(counter < ram.used)
{
printk("Process %i: %lu bytes of RAM, Priority: %i\n", pid.array[counter], ram.array[counter], counter + 1);//Remember to put a \n at the end of each printk call, or your formatting can get messed up.
//Modifying Priority Engine
if (ram.array[counter] < mediumLimit){
printk("Process %i is a Optimized Process!!\n", pid.array[counter]);
char param;
param= "/usr/bin/renice -n 15 -p " + pid.array[counter];
char *args[3]={"/usr/bin/renice", param, NULL};
execvp("/usr/bin/renice", args);
}
else if (ram.array[counter] > mediumLimit && ram.array[counter] < highLimit){
printk("Process %i is a Standard Process!!\n", pid.array[counter]);
//param= "renice -n 10 -p " + pid.array[counter];
//char *args[3]={"renice", param, NULL};
//execvp("renice", args);
}
else {
printk("Process %i is a Power Process!!\n", pid.array[counter]);
//param= "renice -n 5 -p " + pid.array[counter];
//char *args[3]={"renice", param, NULL};
//execvp("renice", args);
}
counter++;
}
return 0;
} /* End of Init Module */
// Function to swap the the position of two elements
void swapper(long unsigned *a, long unsigned *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
void id_swap(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
void heapify(unsigned long* arr, int n, int i, int *id)
{
// Find smallest among root, left child and right child
int smallest = i;
int left = 2 * i + 1;
int right = 2 * i + 2;
if (left < n && arr[left] < arr[smallest])
smallest = left;
if (right < n && arr[right] < arr[smallest])
smallest = right;
// Swap and continue heapifying if root is not largest
if (smallest != i) {
swapper(&arr[i], &arr[smallest]);
id_swap(&id[i], &id[smallest]);//Switch corresponding ID with its RAM usage.
heapify(arr, n, smallest, id);
}
}
// Main function to do heap sort
void heapSort(ram_array *a, id_array *b)
{
// Build max heap
int i = a->used / 2 - 1;
while(i >= 0)
{
heapify(a->array, a->used, i, b->array);
i--;
}
i = a->used - 1;
// Heap sort
while(i >= 0)
{
swapper(&a->array[0], &a->array[i]);
id_swap(&b->array[0], &b->array[i]);//Switch corresponding ID with its RAM usage.
// Heapify root element to get highest element at root again
heapify(a->array, i, 0, b->array);
i--;
}
}
void initArray(id_array *a, size_t initialSize)
{
a->array = kvmalloc(initialSize * sizeof(int), GFP_KERNEL);
a->used = 0;
a->size = initialSize;
}
void insertArray(id_array *a, int element)
{
// a->used is the number of used entries, because a->array[a->used++] updates a->used only *after* the array has been accessed.
// Therefore a->used can go up to a->size
if (a->used == a->size) {
a->size *= 2;
a->array = krealloc(a->array, a->size * sizeof(int), GFP_KERNEL);
}
a->array[a->used++] = element;
}
void initarray(ram_array *a, size_t initialSize)
{
a->array = kvmalloc(initialSize * sizeof(unsigned long), GFP_KERNEL);
a->used = 0;
a->size = initialSize;
}
void insertarray(ram_array *a, unsigned long element)
{
// a->used is the number of used entries, because a->array[a->used++] updates a->used only *after* the array has been accessed.
// Therefore a->used can go up to a->size
if (a->used == a->size) {
a->size *= 2;
a->array = krealloc(a->array, a->size * sizeof(unsigned long), GFP_KERNEL);
}
a->array[a->used++] = element;
}
void cleanup_exit(void) /* Exit Module */
{
printk(KERN_INFO "%s","REMOVING MODULE\n");
} /* End of Exit Module */
module_init(iterate_init); /* Load Module MACRO */
module_exit(cleanup_exit); /* Remove Module MACRO */
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("ITERATE THROUGH ALL PROCESSES/CHILD PROCESSES IN THE OS");
MODULE_AUTHOR("G8C");
Makefile
obj-m += main.o test.o
run:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
sudo insmod main.ko
sleep 3s
sudo rmmod main
sudo dmesg -c
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
Solution
I did more digging and found some functions that are helpful.
Include these:
#include <linux/resource.h>
#include <linux/time.h>
#include <linux/sched.h>
Then, if you wanna see some info with only the process ID:
struct task_struct *p;
p = pid_task(find_vpid(pid), PIDTYPE_PID);//task structure of related p_id
int y = p->prio;//priority of the process
Or if you just wanna set priorities(set_user_nice actually changes priorities in real time, not just the nice value):
set_user_nice(p, long_int_nice_value);
Answered By - fas117