aboutsummaryrefslogtreecommitdiffstats
path: root/litmus/sched_mc_ce.c
diff options
context:
space:
mode:
authorChristopher Kenna <cjk@cs.unc.edu>2011-09-08 02:00:07 -0400
committerChristopher Kenna <cjk@cs.unc.edu>2011-09-08 02:09:43 -0400
commit87c74e28dbad17050783cb30278561f451677152 (patch)
tree199631a1a6d6ec28fa01b35922c901f1118b2ad1 /litmus/sched_mc_ce.c
parent13bd30ca0d37239a3755c25748ded00c265bcc58 (diff)
Untested proc code added.
Diffstat (limited to 'litmus/sched_mc_ce.c')
-rw-r--r--litmus/sched_mc_ce.c302
1 files changed, 293 insertions, 9 deletions
diff --git a/litmus/sched_mc_ce.c b/litmus/sched_mc_ce.c
index b44012822532..8ed960c8729c 100644
--- a/litmus/sched_mc_ce.c
+++ b/litmus/sched_mc_ce.c
@@ -6,27 +6,31 @@
6 */ 6 */
7 7
8#include <asm/atomic.h> 8#include <asm/atomic.h>
9#include <asm/uaccess.h>
9 10
10#include <linux/module.h> 11#include <linux/module.h>
11#include <linux/percpu.h> 12#include <linux/percpu.h>
12#include <linux/hrtimer.h> 13#include <linux/hrtimer.h>
13#include <linux/pid.h> 14#include <linux/pid.h>
14#include <linux/sched.h> 15#include <linux/sched.h>
16#include <linux/proc_fs.h>
15 17
16#include <litmus/litmus.h> 18#include <litmus/litmus.h>
17#include <litmus/sched_plugin.h> 19#include <litmus/sched_plugin.h>
18#include <litmus/rt_domain.h> 20#include <litmus/rt_domain.h>
19#include <litmus/rt_param.h> 21#include <litmus/rt_param.h>
20#include <litmus/sched_mc.h> 22#include <litmus/sched_mc.h>
23#include <litmus/litmus_proc.h>
21 24
22static struct sched_plugin mc_ce_plugin __cacheline_aligned_in_smp; 25static struct sched_plugin mc_ce_plugin __cacheline_aligned_in_smp;
23 26
24#define tsk_mc_data(t) (tsk_rt(t)->mc_data) 27#define tsk_mc_data(t) (tsk_rt(t)->mc_data)
25#define tsk_mc_crit(t) (tsk_mc_data(t)->mc_task.crit) 28#define tsk_mc_crit(t) (tsk_mc_data(t)->mc_task.crit)
26#define is_active_plugin() (litmus == mc_ce_plugin) 29#define is_active_plugin() (litmus == &mc_ce_plugin)
27 30
28static atomic_t start_time_set = ATOMIC_INIT(0); 31static atomic_t start_time_set = ATOMIC_INIT(0);
29static atomic64_t start_time = ATOMIC64_INIT(0); 32static atomic64_t start_time = ATOMIC64_INIT(0);
33static struct proc_dir_entry *mc_ce_dir = NULL, *ce_file = NULL;
30 34
31/* 35/*
32 * Cache the budget along with the struct PID for a task so that we don't need 36 * Cache the budget along with the struct PID for a task so that we don't need
@@ -35,7 +39,9 @@ static atomic64_t start_time = ATOMIC64_INIT(0);
35 */ 39 */
36struct ce_dom_pid_entry { 40struct ce_dom_pid_entry {
37 struct pid *pid; 41 struct pid *pid;
42 /* execution cost (sometimes called budget) */
38 lt_t exec_cost; 43 lt_t exec_cost;
44 /* accumulated (summed) exec costs, including this one */
39 lt_t acc_time; 45 lt_t acc_time;
40}; 46};
41 47
@@ -470,12 +476,38 @@ static struct sched_plugin mc_ce_plugin __cacheline_aligned_in_smp = {
470 .deactivate_plugin = mc_ce_deactivate_plugin, 476 .deactivate_plugin = mc_ce_deactivate_plugin,
471}; 477};
472 478
479static void clear_pid_entries(void)
480{
481 int cpu, entry;
482 domain_t *dom;
483 struct ce_dom_data *ce_data;
484
485 for_each_online_cpu(cpu) {
486 dom = &per_cpu(mc_ce_doms, cpu);
487 ce_data = dom->data;
488 ce_data->num_pid_entries = 0;
489 ce_data->cycle_time = 0;
490 for (entry = 0; entry < CONFIG_PLUGIN_MC_LEVEL_A_MAX_TASKS;
491 ++entry) {
492 if (NULL != ce_data->pid_entries[entry].pid) {
493 put_pid(ce_data->pid_entries[entry].pid);
494 ce_data->pid_entries[entry].pid = NULL;
495 }
496 ce_data->pid_entries[entry].exec_cost = 0;
497 ce_data->pid_entries[entry].acc_time = 0;
498 }
499 }
500}
501
502static int setup_proc(void);
503
473static int __init init_sched_mc_ce(void) 504static int __init init_sched_mc_ce(void)
474{ 505{
475 struct ce_dom_data *ce_data; 506 struct ce_dom_data *ce_data;
476 domain_t *dom; 507 domain_t *dom;
477 int cpu, i; 508 int cpu, err;
478 509
510 clear_pid_entries();
479 for_each_online_cpu(cpu) { 511 for_each_online_cpu(cpu) {
480 dom = &per_cpu(mc_ce_doms, cpu); 512 dom = &per_cpu(mc_ce_doms, cpu);
481 pd_domain_init(dom, NULL, NULL, NULL, NULL); 513 pd_domain_init(dom, NULL, NULL, NULL, NULL);
@@ -484,17 +516,269 @@ static int __init init_sched_mc_ce(void)
484 hrtimer_init(&ce_data->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); 516 hrtimer_init(&ce_data->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
485 hrtimer_start_on_info_init(&ce_data->timer_info); 517 hrtimer_start_on_info_init(&ce_data->timer_info);
486 ce_data->cpu = cpu; 518 ce_data->cpu = cpu;
487 ce_data->num_pid_entries = 0;
488 ce_data->cycle_time = 0;
489 ce_data->timer.function = timer_callback; 519 ce_data->timer.function = timer_callback;
520 }
521 err = setup_proc();
522 if (!err)
523 err = register_sched_plugin(&mc_ce_plugin);
524 return err;
525}
526
527#define BUF_SIZE PAGE_SIZE
528static int write_into_proc(char *proc_buf, const int proc_size, char *fmt, ...)
529{
530 static char buf[BUF_SIZE];
531 int n;
532 va_list args;
533
534 va_start(args, fmt);
535 n = vscnprintf(buf, BUF_SIZE, fmt, args);
536 va_end(args);
537 if (BUF_SIZE <= n || proc_size <= n - 1) {
538 /* too big for formatting buffer or proc (less null byte) */
539 n = -EINVAL;
540 goto out;
541 }
542 memcpy(proc_buf, buf, n - 1);
543out:
544 return n;
545}
546#undef BUF_SIZE
547
548/*
549 * Writes a PID entry to the procfs.
550 */
551#define PID_SPACE 15
552#define TASK_INFO_BUF (PID_SPACE + TASK_COMM_LEN)
553static int write_pid_entry(char *page, const int count, const int cpu,
554 const int task, struct ce_dom_pid_entry *pid_entry)
555{
556 static char task_info[TASK_INFO_BUF];
557 struct task_struct *ts;
558 int n = 0, err, ti_n;
559 char *ti_b;
560
561 if (pid_entry->pid) {
562 rcu_read_lock();
563 ts = pid_task(pid_entry->pid, PIDTYPE_PID);
564 rcu_read_unlock();
565
566 /* get some information about the task */
567 if (ts) {
568 ti_b = task_info;
569 ti_n = snprintf(ti_b, PID_SPACE, "%d", ts->pid);
570 if (PID_SPACE <= ti_n)
571 ti_n = PID_SPACE - 1;
572 ti_b += ti_n;
573 *ti_b = ' '; /* nuke the null byte */
574 ti_b++;
575 get_task_comm(ti_b, ts);
576 task_info[TASK_INFO_BUF - 1] = '\0';
577 } else {
578 const char *msg = "pid_task() failed :(";
579 strncpy(task_info, msg, sizeof(msg));
580 }
581
582 } else
583 strncpy(task_info, "no", 3);
584
585 err = write_into_proc(page, count - n, "# task: %s\n", task_info);
586 if (err < 0) {
587 n = -ENOSPC;
588 goto out;
589 }
590 n += err;
591 err = write_into_proc(page, count - n, "%d, %d, %llu\n",
592 cpu, task, pid_entry->exec_cost);
593 if (err < 0) {
594 n = -ENOSPC;
595 goto out;
596 }
597 n =+ err;
598out:
599 return n;
600}
601#undef PID_SPACE
602#undef TASK_INFO_BUF
490 603
491 for (i = 0; i < CONFIG_PLUGIN_MC_LEVEL_A_MAX_TASKS; ++i) { 604/*
492 ce_data->pid_entries[i].pid = NULL; 605 * Called when the user-land reads from proc.
493 ce_data->pid_entries[i].exec_cost = 0; 606 */
494 ce_data->pid_entries[i].acc_time = 0; 607static int proc_read_ce_file(char *page, char **start, off_t off, int count,
608 int *eof, void *data)
609{
610 int n = 0, err, cpu, t;
611 struct ce_dom_data *ce_data;
612 domain_t *dom;
613
614 if (off > 0) {
615 *eof = 1;
616 return 0;
617 }
618
619 for_each_online_cpu(cpu) {
620 dom = &per_cpu(mc_ce_doms, cpu);
621 ce_data = dom->data;
622 for (t = 0; t < ce_data->num_pid_entries; ++t) {
623 err = write_pid_entry(page, count - n,
624 cpu, t, &ce_data->pid_entries[t]);
625 if (err < 0) {
626 n = -ENOSPC;
627 goto out;
628 }
629 n += err;
495 } 630 }
496 } 631 }
497 return register_sched_plugin(&mc_ce_plugin); 632 *eof = 1;
633out:
634 return n;
635}
636
637/*
638 * Skip a commented line.
639 */
640static int skip_comment(const char *buf, const unsigned long max)
641{
642 unsigned long i = 0;
643 const char *c = buf;
644 if (0 == max || !c || *c != '#')
645 return 0;
646 ++c; ++i;
647 for (; i < max; ++i) {
648 if (*c == '\n') {
649 ++c; ++i;
650 break;
651 }
652 ++c;
653 }
654 return i;
655}
656
657/* a budget of 1 millisecond is probably reasonable */
658#define BUDGET_THRESHOLD 1000000ULL
659static int setup_pid_entry(const int cpu, const int task, const lt_t budget)
660{
661 domain_t *dom = &per_cpu(mc_ce_doms, cpu);
662 struct ce_dom_data *ce_data = dom->data;
663 struct ce_dom_pid_entry *new_entry;
664 int err = 0;
665
666 /* check the inputs */
667 if (cpu < 0 || cpu >= NR_CPUS || task < 1 || task > PID_MAX_DEFAULT ||
668 budget < 1) {
669 printk(KERN_INFO "litmus: bad cpu or task ID sent to "
670 "MC-CE proc\n");
671 err = -EINVAL;
672 goto out;
673 }
674 /* check for small budgets */
675 if (BUDGET_THRESHOLD > budget) {
676 printk(KERN_CRIT "litmus: you gave a small budget for an "
677 "MC-CE task; that might be an issue.\n");
678 }
679 /* check that we have space for a new entry */
680 if (CONFIG_PLUGIN_MC_LEVEL_A_MAX_TASKS <= ce_data->num_pid_entries) {
681 printk(KERN_INFO "litmus: too many MC-CE tasks for cpu "
682 "%d\n", cpu);
683 err = -EINVAL;
684 goto out;
685 }
686 /* add the new entry */
687 new_entry = &ce_data->pid_entries[ce_data->num_pid_entries];
688 BUG_ON(NULL != new_entry->pid);
689 new_entry->exec_cost = budget;
690 new_entry->acc_time = ce_data->cycle_time + budget;
691 /* update the domain entry */
692 ce_data->cycle_time += budget;
693 ce_data->num_pid_entries++;
694out:
695 return err;
696}
697#undef BUDGET_THRESHOLD
698
699/*
700 * Called when the user-land writes to proc.
701 *
702 * Error checking is quite minimal. Format is:
703 * <cpu>, <process ID>, <budget>
704 */
705#define PROCFS_MAX_SIZE PAGE_SIZE
706static int proc_write_ce_file(struct file *file, const char __user *buffer,
707 unsigned long count, void *data)
708{
709 static char kbuf[PROCFS_MAX_SIZE];
710 char *c = kbuf, *c_skipped;
711 int cpu, task, cnt = 0, chars_read, converted, err;
712 lt_t budget;
713
714 if (is_active_plugin()) {
715 printk(KERN_INFO "litmus: can't edit MC-CE proc when plugin "
716 "active\n");
717 cnt = -EINVAL;
718 goto out;
719 }
720
721 if (count > PROCFS_MAX_SIZE) {
722 cnt = -EINVAL;
723 goto out;
724 }
725
726 if (copy_from_user(kbuf, buffer, count)) {
727 cnt = -EFAULT;
728 goto out;
729 }
730 clear_pid_entries();
731 while (cnt < count) {
732 c_skipped = skip_spaces(c);
733 if (c_skipped != c) {
734 chars_read = c_skipped - c;
735 cnt += chars_read;
736 c += chars_read;
737 continue;
738 }
739 if (*c == '#') {
740 chars_read = skip_comment(c, count - cnt);
741 cnt += chars_read;
742 c += chars_read;
743 continue;
744 }
745 chars_read = sscanf(c, "%d, %d, %llu%n", &cpu, &task, &budget,
746 &converted);
747 if (3 != converted) {
748 cnt = -EINVAL;
749 goto out;
750 }
751 cnt += chars_read;
752 c += chars_read;
753 err = setup_pid_entry(cpu, task, budget);
754 if (err) {
755 cnt = -EINVAL;
756 goto out;
757 }
758 }
759out:
760 return cnt;
761}
762#undef PROCFS_MAX_SIZE
763
764static int setup_proc(void)
765{
766 int err;
767 err = make_plugin_proc_dir(&mc_ce_plugin, &mc_ce_dir);
768 if (err) {
769 printk(KERN_ERR "could not create MC-CE procfs dir.\n");
770 goto out;
771 }
772 ce_file = create_proc_entry("ce_file", 0644, mc_ce_dir);
773 if (!ce_file) {
774 printk(KERN_ERR "could not create MC-CE procfs file.\n");
775 err = -EIO;
776 goto out;
777 }
778 ce_file->read_proc = proc_read_ce_file;
779 ce_file->write_proc = proc_write_ce_file;
780out:
781 return err;
498} 782}
499 783
500module_init(init_sched_mc_ce); 784module_init(init_sched_mc_ce);