From: Daniel P. <d.p...@gm...> - 2005-04-13 21:38:33
|
Hi, Here we have a patch that brings the possibility to statically assign a=20 given task (application) to a dpm task-state. If we want mozilla to run in task state "task-2" we make like this: #echo -n "assign mozilla task-2" > /sys/dpm/task_assignment So, whenever mozilla becomes a task it will go to "task-2" task state. if we issue: #cat /sys/dpm/task_assignment=20 We have: #DPM task assignment - [ mozilla] [task-2]. And all other assigned applications. This enables the possibility of assign applications to certain tasks states= =20 in boot scripts. It makes dpm usage easier from the user point of view. This patch should be applied over: 2.6.11 (www.kernel.org <http://www.kernel.org>) patch-2.6.11-omap1 (www.muru.com <http://www.muru.com>) dpm-2.6.11.patch (http://sourceforge.net/projects/dynamicpower/) dpm-2.6.10-omap.patch (http://sourceforge.net/projects/dynamicpower/) It was tested in OMAP Innovator1510.=20 Tests and comments are very welcome. Daniel Petrini -------------------------- 10LE - Linux Nokia Institute of Tecnology - INdT Manaus - Brazil ------------------------------------------------------------------- diff -uprN linux-2.6.11-vanilla-dpm-2611-orig/drivers/dpm/dpm.c=20 linux-2.6.11-vanilla-dpm-2611/drivers/dpm/dpm.c --- linux-2.6.11-vanilla-dpm-2611-orig/drivers/dpm/dpm.c 2005-04-13 08:36: 28.000000000 -0400 +++ linux-2.6.11-vanilla-dpm-2611/drivers/dpm/dpm.c 2005-04-13 16:06: 21.000000000 -0400 @@ -175,6 +175,9 @@ LIST_HEAD(dpm_policies); LIST_HEAD(dpm_classes); LIST_HEAD(dpm_opts); +/* currently installed task assignments*/ +LIST_HEAD(dpm_task_assignments); + DECLARE_MUTEX(_dpm_lock); spinlock_t dpm_policy_lock =3D SPIN_LOCK_UNLOCKED; @@ -498,6 +501,47 @@ dpm_set_os(dpm_state_t new_state) EXPORT_SYMBOL(dpm_set_os); /**************************************************************************= *** + * verify task assignment + *=20 + * Function to verify to which task-state a starting task will be assigned= . +=20 ***************************************************************************= */ +int +dpm_verify_task_assignment(struct task_struct *task) +{ + struct list_head *p; + int task_state; +=20 + if (dpm_lock_interruptible()) + return -ERESTARTSYS; + + /* Searches this task cmdline at /sys/dpm/task_assignment entry */ +=20 + /* Assign it or default case not found */ + list_for_each(p, &dpm_task_assignments)=20 + /* If the newly created process name matches task assignm. ..*/ + if (strcmp(task->comm, ((struct dpm_task_assignment *)=20 + list_entry(p, struct dpm_task_assignment, list))->name) =3D=3D 0)=20 + /* Retrieve the task state of that process */ + for (task_state =3D DPM_TASK_STATE - DPM_TASK_STATE_LIMIT; + task_state <=3D DPM_TASK_STATE + DPM_TASK_STATE_LIMIT;=20 + task_state++) +=20 + if (strcmp(dpm_state_names[task_state],((struct dpm_task_assignment*) + list_entry(p, struct dpm_task_assignment, list))->state_name ) =3D=3D 0){ + task->dpm_state =3D task_state; + return 0; + } +=20 + /* Not listed - default behavior */ + task->dpm_state =3D DPM_TASK_STATE; + + dpm_unlock(); + + return 0; +} +EXPORT_SYMBOL(dpm_verify_task_assignment); + +/*************************************************************************= **** * initialize the DPM ***************************************************************************= **/ int @@ -1003,6 +1047,79 @@ dpm_set_op_state(const char *name) return -ENOENT; } +/*************************************************************************= **** + * Creation and destruction of task assignment data +=20 ***************************************************************************= **/ +int +_dpm_create_task_assignment(const char *app_name, const char *task_state, + struct dpm_task_assignment **p) +{ + struct dpm_task_assignment *tsk_ast; + + /* get the memory for it */ + if (!=20 + (tsk_ast =3D (struct dpm_task_assignment *) kmalloc=20 + (sizeof(struct dpm_task_assignment), GFP_KERNEL))) { + return -ENOMEM; + } + + memset(tsk_ast, 0, sizeof(struct dpm_task_assignment)); + + /* Allocate and store the strings*/ + if (!(tsk_ast->name =3D + (char *) kmalloc(strlen(app_name) + 1, GFP_KERNEL ))) { + kfree(tsk_ast); + return -ENOMEM; + } + strcpy (tsk_ast->name, app_name); + + if (!(tsk_ast->state_name =3D (char *) kmalloc(strlen(task_state) + 1, + GFP_KERNEL ))) { + kfree(tsk_ast); + return -ENOMEM; + } + strcpy(tsk_ast->state_name, task_state); + + INIT_LIST_HEAD(&tsk_ast->list); + *p =3D tsk_ast; + + return 0; +} + +int=20 +dpm_create_task_assignment(const char *app_name, const char *task_state) +{ + struct dpm_task_assignment * tsk_ast; + int ret; + + dpm_lock(); +=20 + /* ensure unique application name entry */ + list_find(tsk_ast, app_name, dpm_task_assignments,=20 + struct dpm_task_assignment); + if (tsk_ast) { + dpm_unlock(); + return -EEXIST; + } +=20 + /* create the assignment */ + ret =3D _dpm_create_task_assignment(app_name, task_state, &tsk_ast); + + if (!ret) + list_add(&tsk_ast->list, &dpm_task_assignments); + + dpm_unlock(); + return ret; +} + +void +destroy_task_assignment(struct dpm_task_assignment *tsk_ast) +{ + list_del(&tsk_ast->list); + kfree(tsk_ast->name); + kfree(tsk_ast->state_name); + kfree(tsk_ast); +} /**************************************************************************= *** * terminate the DPM @@ -1033,8 +1150,11 @@ dynamicpower_terminate(void) while (!list_empty(&dpm_classes)) destroy_class(list_entry(dpm_classes.next, struct dpm_class, list)); - - + while (!list_empty(&dpm_task_assignments)) + destroy_task_assignment(list_entry(dpm_task_assignments.next, + struct dpm_task_assignment, list)); +=20 +=20 mb(); dpm_unlock(); diff -uprN linux-2.6.11-vanilla-dpm-2611-orig/drivers/dpm/dpm-ui.c=20 linux-2.6.11-vanilla-dpm-2611/drivers/dpm/dpm-ui.c --- linux-2.6.11-vanilla-dpm-2611-orig/drivers/dpm/dpm-ui.c 2005-04-13=20 08:36:28.000000000 -0400 +++ linux-2.6.11-vanilla-dpm-2611/drivers/dpm/dpm-ui.c 2005-04-13 16:07: 44.000000000 -0400 @@ -120,8 +120,88 @@ static ssize_t dpm_control_store(struct=20 dpm_attr(control,dpm_control); +/* + * Reads task-assignment + */ + +static ssize_t dpm_task_assignment_show(struct subsystem * subsys, char *= =20 buf) +{ + ssize_t len =3D 0; + struct list_head *p; + + if (dpm_lock_interruptible()) + return -ERESTARTSYS; + + if (!dpm_enabled) { + len +=3D sprintf(buf, "DPM disabled\n"); + } else { +=20 + list_for_each(p, &dpm_task_assignments) { + printk("DPM task assignment - [%10s] [%6s].\n", + ((struct dpm_task_assignment *)=20 + list_entry(p, struct dpm_task_assignment, list))->name, + ((struct dpm_task_assignment *) + list_entry(p, struct dpm_task_assignment, list))->state_name ); + } +=20 + } + + dpm_unlock(); + return len; +} + +/*************************************************************************= **** + * Treats sys entries and stores properly. writing in=20 /sys/dpm/task_assignment + * Receives something like "assign mozilla task-2" +=20 ***************************************************************************= **/ +static ssize_t dpm_task_assignment_store(struct subsystem * subsys,=20 + const char * buf, size_t n) +{ + int error =3D 0; + char *tbuf =3D NULL; + char *token[MAXTOKENS]; + int ntoks =3D tokenizer(&tbuf, buf, n, (char **) &token, MAXTOKENS); + int task_state; + int valid_input =3D 0; +=20 + if (ntoks <=3D 0) { + error =3D ntoks; + goto out; + } + + if (strcmp(token[0],"assign") =3D=3D 0) { + + /* Consistency check */ + for (task_state =3D DPM_TASK_STATE - DPM_TASK_STATE_LIMIT; + task_state <=3D DPM_TASK_STATE + DPM_TASK_STATE_LIMIT;=20 + task_state++) + if (strcmp(dpm_state_names[task_state], token[2]) =3D=3D 0) { + printk ("Associate [%10s] <-> [%6s]\n", token[1], token[2]); + error =3D dpm_create_task_assignment(token[1], token[2]); + valid_input =3D 1; + }=20 + if (!valid_input) { + printk ("DPM - Invalid input\n"); + error =3D -EINVAL; + goto out; + } +=20 +=20 + } else + error =3D -EINVAL; + + out: + if (tbuf) + kfree(tbuf); + return error ? error : n; +=20 +} + +dpm_attr(task_assignment,dpm_task_assignment); + static struct attribute * g[] =3D { &dpm_control_attr.attr, + &dpm_task_assignment_attr.attr,=20 NULL, }; diff -uprN linux-2.6.11-vanilla-dpm-2611-orig/fs/exec.c=20 linux-2.6.11-vanilla-dpm-2611/fs/exec.c --- linux-2.6.11-vanilla-dpm-2611-orig/fs/exec.c 2005-04-13 08:36: 28.000000000 -0400 +++ linux-2.6.11-vanilla-dpm-2611/fs/exec.c 2005-04-13 16:08:23.000000000-0= 400 @@ -48,6 +48,7 @@ #include <linux/syscalls.h> #include <linux/rmap.h> #include <linux/acct.h> +#include <linux/dpm.h> #include <asm/uaccess.h> #include <asm/mmu_context.h> @@ -1194,6 +1195,9 @@ int do_execve(char * filename, acct_update_integrals(); update_mem_hiwater(); kfree(bprm); + + dpm_verify_task_assignment(current); +=20 return retval; } diff -uprN linux-2.6.11-vanilla-dpm-2611-orig/include/linux/dpm.h=20 linux-2.6.11-vanilla-dpm-2611/include/linux/dpm.h --- linux-2.6.11-vanilla-dpm-2611-orig/include/linux/dpm.h 2005-04-13 08:36= : 29.000000000 -0400 +++ linux-2.6.11-vanilla-dpm-2611/include/linux/dpm.h 2005-04-13 16:08: 08.000000000 -0400 @@ -166,6 +166,14 @@ struct dpm_policy { struct dpm_stats stats; /* statistics */ }; +/* Internal representation of the application and task-states relation*/ +struct dpm_task_assignment { + char *name; /* User space app*/ + char *state_name; /* DPM state name */ + struct list_head list; /* Store assignements */ +}; + + /* * internal use utility functions for use by DPM */ @@ -277,6 +285,9 @@ extern void dpm_sysfs_destroy_op(struct=20 extern int proc_pid_dpm_read(struct task_struct*,char*); +/* Task assignment */ +int dpm_verify_task_assignment(struct task_struct *task); +int dpm_create_task_assignment(const char *app_name, const char=20 *task_state); /* * global data for power management system @@ -286,6 +297,9 @@ extern int proc_pid_dpm_read(struct task extern struct list_head dpm_policies; extern struct list_head dpm_classes; extern struct list_head dpm_opts; + +extern struct list_head dpm_task_assignments; + extern struct semaphore dpm_policy_sem; extern spinlock_t dpm_policy_lock; |
From: Todd P. <tp...@mv...> - 2005-04-16 01:29:56
|
Hello Daniel -- I've been too busy as of late to look into this in depth, but I am curious to hear people's requests for, or experience with, such ability to automatically assign DPM task states at exec time according to custom rules (such as by command name, as with this patch). Admittedly, most folks using DPM are using it in tightly-controlled mobile phone / PDA consumer electronics devices, where a main menu application can make these decisions according to its own logic, instead of a general-purpose interactive desktop/server environment with no central control over execution of apps. Ways of applying heuristics to power management characteristics of new processes without searching a list at each process exec would be a plus, although custom ELF header extensions and the like are messy as well. Thanks, -- Todd |
From: Daniel P. <d.p...@gm...> - 2005-04-20 21:05:59
|
Hello Todd, On 4/15/05, Todd Poynor <tp...@mv...> wrote: >=20 > Hello Daniel -- I've been too busy as of late to look into this in > depth, but I am curious to hear people's requests for, or experience > with, such ability to automatically assign DPM task states at exec time > according to custom rules (such as by command name, as with this patch). Admittedly, most folks using DPM are using it in tightly-controlled > mobile phone / PDA consumer electronics devices, where a main menu > application can make these decisions according to its own logic, instead > of a general-purpose interactive desktop/server environment with no > central control over execution of apps.=20 OK, I Agree but nonetheless this patch can be used by Centrino users who can assign task states to some process that will likely run. So, after assigning some normally used applications one can have power savings assured after configuring it in initscripts.=20 I don't know why DPM has support for centrino as it is not likely to be use= d for mobile phone and PDA consumer goods, but if one of the reasons are broaden the DPM usage sometimes we could look to that side. Even in small linux systems this idea can be used to have a default=20 and starting configuration for dpm, although small systems requiring power savings needs much more than this. Ways of applying heuristics to > power management characteristics of new processes without searching a > list at each process exec would be a plus, although custom ELF header > extensions and the like are messy as well. Thanks, That work was made to have some experience and knowledge of DPM, now I'm looking for new ideas to try to have improvements and suggestions to DPM. And I think, as well, that applying heuristics to process=20 characteristics may lead to great improvements in power management. I think of some simple calculations to have data to help to decide to which= =20 task-state should a process be moved. To a given process calculate some values like: 1) CPU usage in last minute/ Total CPU=20 2) I/O usage in last minute, how much time blocked - here the type of I/O must be of interest, network more important than display... 3) Process priority 4) Some value from the system manager (which spawns controlled apps) 5) ... Actually I'm looking for these metrics that could help to decide. It seems that all of these should be implemented in user-space, to run as a daemon unless one need to export some information from kernel.=20 OK. That is it. If you have some pointers to follow I'm open to that. Daniel --=20 10LE - Linux Nokia Institute of Tecnology - INdT Manaus - Brazil |