1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2014 Intel Corporation
12 #include <sys/types.h>
13 #include <sys/epoll.h>
14 #include <sys/queue.h>
18 #include <rte_memory.h>
19 #include <rte_malloc.h>
20 #include <rte_atomic.h>
21 #include <rte_cycles.h>
22 #include <rte_ethdev.h>
23 #include <rte_pmd_i40e.h>
25 #include <libvirt/libvirt.h>
26 #include "channel_monitor.h"
27 #include "channel_commands.h"
28 #include "channel_manager.h"
29 #include "power_manager.h"
30 #include "oob_monitor.h"
32 #define RTE_LOGTYPE_CHANNEL_MONITOR RTE_LOGTYPE_USER1
34 #define MAX_EVENTS 256
36 uint64_t vsi_pkt_count_prev[384];
37 uint64_t rdtsc_prev[384];
39 double time_period_ms = 1;
40 static volatile unsigned run_loop = 1;
41 static int global_event_fd;
42 static unsigned int policy_is_set;
43 static struct epoll_event *global_events_list;
44 static struct policy policies[MAX_VMS];
46 void channel_monitor_exit(void)
49 rte_free(global_events_list);
53 core_share(int pNo, int z, int x, int t)
55 if (policies[pNo].core_share[z].pcpu == lvm_info[x].pcpus[t]) {
56 if (strcmp(policies[pNo].pkt.vm_name,
57 lvm_info[x].vm_name) != 0) {
58 policies[pNo].core_share[z].status = 1;
59 power_manager_scale_core_max(
60 policies[pNo].core_share[z].pcpu);
66 core_share_status(int pNo)
69 int noVms, noVcpus, z, x, t;
71 get_all_vm(&noVms, &noVcpus);
73 /* Reset Core Share Status. */
74 for (z = 0; z < noVcpus; z++)
75 policies[pNo].core_share[z].status = 0;
77 /* Foreach vcpu in a policy. */
78 for (z = 0; z < policies[pNo].pkt.num_vcpu; z++) {
79 /* Foreach VM on the platform. */
80 for (x = 0; x < noVms; x++) {
81 /* Foreach vcpu of VMs on platform. */
82 for (t = 0; t < lvm_info[x].num_cpus; t++)
83 core_share(pNo, z, x, t);
89 get_pcpu_to_control(struct policy *pol)
92 /* Convert vcpu to pcpu. */
101 RTE_LOG(INFO, CHANNEL_MONITOR, "Looking for pcpu for %s\n",
103 get_info_vm(pol->pkt.vm_name, &info);
105 for (count = 0; count < pol->pkt.num_vcpu; count++) {
106 mask_u64b = info.pcpu_mask[pol->pkt.vcpu_to_control[count]];
107 for (pcpu = 0; mask_u64b; mask_u64b &= ~(1ULL << pcpu++)) {
108 if ((mask_u64b >> pcpu) & 1) {
109 if (pol->pkt.policy_to_use == BRANCH_RATIO) {
110 ci->cd[pcpu].oob_enabled = 1;
111 ret = add_core_to_monitor(pcpu);
113 printf("Monitoring pcpu %d via Branch Ratio\n",
116 printf("Failed to start OOB Monitoring pcpu %d\n",
120 pol->core_share[count].pcpu = pcpu;
121 printf("Monitoring pcpu %d\n", pcpu);
129 get_pfid(struct policy *pol)
134 for (i = 0; i < pol->pkt.nb_mac_to_monitor; i++) {
136 RTE_ETH_FOREACH_DEV(x) {
137 ret = rte_pmd_i40e_query_vfid_by_mac(x,
138 (struct ether_addr *)&(pol->pkt.vfid[i]));
139 if (ret != -EINVAL) {
144 if (ret == -EINVAL || ret == -ENOTSUP || ret == ENODEV) {
145 RTE_LOG(INFO, CHANNEL_MONITOR,
146 "Error with Policy. MAC not found on "
157 update_policy(struct channel_packet *pkt)
160 unsigned int updated = 0;
163 for (i = 0; i < MAX_VMS; i++) {
164 if (strcmp(policies[i].pkt.vm_name, pkt->vm_name) == 0) {
165 policies[i].pkt = *pkt;
166 get_pcpu_to_control(&policies[i]);
167 if (get_pfid(&policies[i]) == -1) {
171 core_share_status(i);
172 policies[i].enabled = 1;
177 for (i = 0; i < MAX_VMS; i++) {
178 if (policies[i].enabled == 0) {
179 policies[i].pkt = *pkt;
180 get_pcpu_to_control(&policies[i]);
181 if (get_pfid(&policies[i]) == -1)
183 core_share_status(i);
184 policies[i].enabled = 1;
193 get_pkt_diff(struct policy *pol)
196 uint64_t vsi_pkt_count,
198 vsi_pkt_count_prev_total = 0;
199 double rdtsc_curr, rdtsc_diff, diff;
201 struct rte_eth_stats vf_stats;
203 for (x = 0; x < pol->pkt.nb_mac_to_monitor; x++) {
206 if (rte_pmd_i40e_get_vf_stats(x, pol->pfid[x], &vf_stats) == 0)
207 vsi_pkt_count = vf_stats.ipackets;
211 vsi_pkt_total += vsi_pkt_count;
213 vsi_pkt_count_prev_total += vsi_pkt_count_prev[pol->pfid[x]];
214 vsi_pkt_count_prev[pol->pfid[x]] = vsi_pkt_count;
217 rdtsc_curr = rte_rdtsc_precise();
218 rdtsc_diff = rdtsc_curr - rdtsc_prev[pol->pfid[x-1]];
219 rdtsc_prev[pol->pfid[x-1]] = rdtsc_curr;
221 diff = (vsi_pkt_total - vsi_pkt_count_prev_total) *
222 ((double)rte_get_tsc_hz() / rdtsc_diff);
228 apply_traffic_profile(struct policy *pol)
234 diff = get_pkt_diff(pol);
236 RTE_LOG(INFO, CHANNEL_MONITOR, "Applying traffic profile\n");
238 if (diff >= (pol->pkt.traffic_policy.max_max_packet_thresh)) {
239 for (count = 0; count < pol->pkt.num_vcpu; count++) {
240 if (pol->core_share[count].status != 1)
241 power_manager_scale_core_max(
242 pol->core_share[count].pcpu);
244 } else if (diff >= (pol->pkt.traffic_policy.avg_max_packet_thresh)) {
245 for (count = 0; count < pol->pkt.num_vcpu; count++) {
246 if (pol->core_share[count].status != 1)
247 power_manager_scale_core_med(
248 pol->core_share[count].pcpu);
250 } else if (diff < (pol->pkt.traffic_policy.avg_max_packet_thresh)) {
251 for (count = 0; count < pol->pkt.num_vcpu; count++) {
252 if (pol->core_share[count].status != 1)
253 power_manager_scale_core_min(
254 pol->core_share[count].pcpu);
260 apply_time_profile(struct policy *pol)
266 char time_string[40];
268 /* Obtain the time of day, and convert it to a tm struct. */
269 gettimeofday(&tv, NULL);
270 ptm = localtime(&tv.tv_sec);
271 /* Format the date and time, down to a single second. */
272 strftime(time_string, sizeof(time_string), "%Y-%m-%d %H:%M:%S", ptm);
274 for (x = 0; x < HOURS; x++) {
276 if (ptm->tm_hour == pol->pkt.timer_policy.busy_hours[x]) {
277 for (count = 0; count < pol->pkt.num_vcpu; count++) {
278 if (pol->core_share[count].status != 1) {
279 power_manager_scale_core_max(
280 pol->core_share[count].pcpu);
281 RTE_LOG(INFO, CHANNEL_MONITOR,
282 "Scaling up core %d to max\n",
283 pol->core_share[count].pcpu);
287 } else if (ptm->tm_hour ==
288 pol->pkt.timer_policy.quiet_hours[x]) {
289 for (count = 0; count < pol->pkt.num_vcpu; count++) {
290 if (pol->core_share[count].status != 1) {
291 power_manager_scale_core_min(
292 pol->core_share[count].pcpu);
293 RTE_LOG(INFO, CHANNEL_MONITOR,
294 "Scaling down core %d to min\n",
295 pol->core_share[count].pcpu);
299 } else if (ptm->tm_hour ==
300 pol->pkt.timer_policy.hours_to_use_traffic_profile[x]) {
301 apply_traffic_profile(pol);
308 apply_workload_profile(struct policy *pol)
313 if (pol->pkt.workload == HIGH) {
314 for (count = 0; count < pol->pkt.num_vcpu; count++) {
315 if (pol->core_share[count].status != 1)
316 power_manager_scale_core_max(
317 pol->core_share[count].pcpu);
319 } else if (pol->pkt.workload == MEDIUM) {
320 for (count = 0; count < pol->pkt.num_vcpu; count++) {
321 if (pol->core_share[count].status != 1)
322 power_manager_scale_core_med(
323 pol->core_share[count].pcpu);
325 } else if (pol->pkt.workload == LOW) {
326 for (count = 0; count < pol->pkt.num_vcpu; count++) {
327 if (pol->core_share[count].status != 1)
328 power_manager_scale_core_min(
329 pol->core_share[count].pcpu);
335 apply_policy(struct policy *pol)
338 struct channel_packet *pkt = &pol->pkt;
340 /*Check policy to use*/
341 if (pkt->policy_to_use == TRAFFIC)
342 apply_traffic_profile(pol);
343 else if (pkt->policy_to_use == TIME)
344 apply_time_profile(pol);
345 else if (pkt->policy_to_use == WORKLOAD)
346 apply_workload_profile(pol);
351 process_request(struct channel_packet *pkt, struct channel_info *chan_info)
355 if (chan_info == NULL)
358 if (rte_atomic32_cmpset(&(chan_info->status), CHANNEL_MGR_CHANNEL_CONNECTED,
359 CHANNEL_MGR_CHANNEL_PROCESSING) == 0)
362 if (pkt->command == CPU_POWER) {
363 core_mask = get_pcpus_mask(chan_info, pkt->resource_id);
364 if (core_mask == 0) {
365 RTE_LOG(ERR, CHANNEL_MONITOR, "Error get physical CPU mask for "
366 "channel '%s' using vCPU(%u)\n", chan_info->channel_path,
367 (unsigned)pkt->unit);
370 if (__builtin_popcountll(core_mask) == 1) {
372 unsigned core_num = __builtin_ffsll(core_mask) - 1;
375 case(CPU_POWER_SCALE_MIN):
376 power_manager_scale_core_min(core_num);
378 case(CPU_POWER_SCALE_MAX):
379 power_manager_scale_core_max(core_num);
381 case(CPU_POWER_SCALE_DOWN):
382 power_manager_scale_core_down(core_num);
384 case(CPU_POWER_SCALE_UP):
385 power_manager_scale_core_up(core_num);
387 case(CPU_POWER_ENABLE_TURBO):
388 power_manager_enable_turbo_core(core_num);
390 case(CPU_POWER_DISABLE_TURBO):
391 power_manager_disable_turbo_core(core_num);
398 case(CPU_POWER_SCALE_MIN):
399 power_manager_scale_mask_min(core_mask);
401 case(CPU_POWER_SCALE_MAX):
402 power_manager_scale_mask_max(core_mask);
404 case(CPU_POWER_SCALE_DOWN):
405 power_manager_scale_mask_down(core_mask);
407 case(CPU_POWER_SCALE_UP):
408 power_manager_scale_mask_up(core_mask);
410 case(CPU_POWER_ENABLE_TURBO):
411 power_manager_enable_turbo_mask(core_mask);
413 case(CPU_POWER_DISABLE_TURBO):
414 power_manager_disable_turbo_mask(core_mask);
423 if (pkt->command == PKT_POLICY) {
424 RTE_LOG(INFO, CHANNEL_MONITOR, "\nProcessing Policy request from Guest\n");
429 /* Return is not checked as channel status may have been set to DISABLED
430 * from management thread
432 rte_atomic32_cmpset(&(chan_info->status), CHANNEL_MGR_CHANNEL_PROCESSING,
433 CHANNEL_MGR_CHANNEL_CONNECTED);
439 add_channel_to_monitor(struct channel_info **chan_info)
441 struct channel_info *info = *chan_info;
442 struct epoll_event event;
444 event.events = EPOLLIN;
445 event.data.ptr = info;
446 if (epoll_ctl(global_event_fd, EPOLL_CTL_ADD, info->fd, &event) < 0) {
447 RTE_LOG(ERR, CHANNEL_MONITOR, "Unable to add channel '%s' "
448 "to epoll\n", info->channel_path);
455 remove_channel_from_monitor(struct channel_info *chan_info)
457 if (epoll_ctl(global_event_fd, EPOLL_CTL_DEL, chan_info->fd, NULL) < 0) {
458 RTE_LOG(ERR, CHANNEL_MONITOR, "Unable to remove channel '%s' "
459 "from epoll\n", chan_info->channel_path);
466 channel_monitor_init(void)
468 global_event_fd = epoll_create1(0);
469 if (global_event_fd == 0) {
470 RTE_LOG(ERR, CHANNEL_MONITOR, "Error creating epoll context with "
471 "error %s\n", strerror(errno));
474 global_events_list = rte_malloc("epoll_events", sizeof(*global_events_list)
475 * MAX_EVENTS, RTE_CACHE_LINE_SIZE);
476 if (global_events_list == NULL) {
477 RTE_LOG(ERR, CHANNEL_MONITOR, "Unable to rte_malloc for "
485 run_channel_monitor(void)
490 n_events = epoll_wait(global_event_fd, global_events_list,
494 for (i = 0; i < n_events; i++) {
495 struct channel_info *chan_info = (struct channel_info *)
496 global_events_list[i].data.ptr;
497 if ((global_events_list[i].events & EPOLLERR) ||
498 (global_events_list[i].events & EPOLLHUP)) {
499 RTE_LOG(DEBUG, CHANNEL_MONITOR, "Remote closed connection for "
501 chan_info->channel_path);
502 remove_channel(&chan_info);
505 if (global_events_list[i].events & EPOLLIN) {
507 int n_bytes, err = 0;
508 struct channel_packet pkt;
510 int buffer_len = sizeof(pkt);
512 while (buffer_len > 0) {
513 n_bytes = read(chan_info->fd,
515 if (n_bytes == buffer_len)
519 RTE_LOG(DEBUG, CHANNEL_MONITOR,
521 "channel '%s' read: %s\n",
522 chan_info->channel_path,
524 remove_channel(&chan_info);
527 buffer = (char *)buffer + n_bytes;
528 buffer_len -= n_bytes;
531 process_request(&pkt, chan_info);
534 rte_delay_us(time_period_ms*1000);
538 for (j = 0; j < MAX_VMS; j++) {
539 if (policies[j].enabled == 1)
540 apply_policy(&policies[j]);