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"
31 #define RTE_LOGTYPE_CHANNEL_MONITOR RTE_LOGTYPE_USER1
33 #define MAX_EVENTS 256
35 uint64_t vsi_pkt_count_prev[384];
36 uint64_t rdtsc_prev[384];
38 double time_period_ms = 1;
39 static volatile unsigned run_loop = 1;
40 static int global_event_fd;
41 static unsigned int policy_is_set;
42 static struct epoll_event *global_events_list;
43 static struct policy policies[MAX_VMS];
45 void channel_monitor_exit(void)
48 rte_free(global_events_list);
52 core_share(int pNo, int z, int x, int t)
54 if (policies[pNo].core_share[z].pcpu == lvm_info[x].pcpus[t]) {
55 if (strcmp(policies[pNo].pkt.vm_name,
56 lvm_info[x].vm_name) != 0) {
57 policies[pNo].core_share[z].status = 1;
58 power_manager_scale_core_max(
59 policies[pNo].core_share[z].pcpu);
65 core_share_status(int pNo)
68 int noVms, noVcpus, z, x, t;
70 get_all_vm(&noVms, &noVcpus);
72 /* Reset Core Share Status. */
73 for (z = 0; z < noVcpus; z++)
74 policies[pNo].core_share[z].status = 0;
76 /* Foreach vcpu in a policy. */
77 for (z = 0; z < policies[pNo].pkt.num_vcpu; z++) {
78 /* Foreach VM on the platform. */
79 for (x = 0; x < noVms; x++) {
80 /* Foreach vcpu of VMs on platform. */
81 for (t = 0; t < lvm_info[x].num_cpus; t++)
82 core_share(pNo, z, x, t);
88 get_pcpu_to_control(struct policy *pol)
91 /* Convert vcpu to pcpu. */
96 RTE_LOG(INFO, CHANNEL_MONITOR, "Looking for pcpu for %s\n",
98 get_info_vm(pol->pkt.vm_name, &info);
100 for (count = 0; count < pol->pkt.num_vcpu; count++) {
101 mask_u64b = info.pcpu_mask[pol->pkt.vcpu_to_control[count]];
102 for (pcpu = 0; mask_u64b; mask_u64b &= ~(1ULL << pcpu++)) {
103 if ((mask_u64b >> pcpu) & 1)
104 pol->core_share[count].pcpu = pcpu;
110 get_pfid(struct policy *pol)
113 int i, x, ret = 0, nb_ports;
115 nb_ports = rte_eth_dev_count();
116 for (i = 0; i < pol->pkt.nb_mac_to_monitor; i++) {
118 for (x = 0; x < nb_ports; x++) {
119 ret = rte_pmd_i40e_query_vfid_by_mac(x,
120 (struct ether_addr *)&(pol->pkt.vfid[i]));
121 if (ret != -EINVAL) {
126 if (ret == -EINVAL || ret == -ENOTSUP || ret == ENODEV) {
127 RTE_LOG(INFO, CHANNEL_MONITOR,
128 "Error with Policy. MAC not found on "
139 update_policy(struct channel_packet *pkt)
142 unsigned int updated = 0;
145 for (i = 0; i < MAX_VMS; i++) {
146 if (strcmp(policies[i].pkt.vm_name, pkt->vm_name) == 0) {
147 policies[i].pkt = *pkt;
148 get_pcpu_to_control(&policies[i]);
149 if (get_pfid(&policies[i]) == -1) {
153 core_share_status(i);
154 policies[i].enabled = 1;
159 for (i = 0; i < MAX_VMS; i++) {
160 if (policies[i].enabled == 0) {
161 policies[i].pkt = *pkt;
162 get_pcpu_to_control(&policies[i]);
163 if (get_pfid(&policies[i]) == -1)
165 core_share_status(i);
166 policies[i].enabled = 1;
175 get_pkt_diff(struct policy *pol)
178 uint64_t vsi_pkt_count,
180 vsi_pkt_count_prev_total = 0;
181 double rdtsc_curr, rdtsc_diff, diff;
183 struct rte_eth_stats vf_stats;
185 for (x = 0; x < pol->pkt.nb_mac_to_monitor; x++) {
188 if (rte_pmd_i40e_get_vf_stats(x, pol->pfid[x], &vf_stats) == 0)
189 vsi_pkt_count = vf_stats.ipackets;
193 vsi_pkt_total += vsi_pkt_count;
195 vsi_pkt_count_prev_total += vsi_pkt_count_prev[pol->pfid[x]];
196 vsi_pkt_count_prev[pol->pfid[x]] = vsi_pkt_count;
199 rdtsc_curr = rte_rdtsc_precise();
200 rdtsc_diff = rdtsc_curr - rdtsc_prev[pol->pfid[x-1]];
201 rdtsc_prev[pol->pfid[x-1]] = rdtsc_curr;
203 diff = (vsi_pkt_total - vsi_pkt_count_prev_total) *
204 ((double)rte_get_tsc_hz() / rdtsc_diff);
210 apply_traffic_profile(struct policy *pol)
216 diff = get_pkt_diff(pol);
218 RTE_LOG(INFO, CHANNEL_MONITOR, "Applying traffic profile\n");
220 if (diff >= (pol->pkt.traffic_policy.max_max_packet_thresh)) {
221 for (count = 0; count < pol->pkt.num_vcpu; count++) {
222 if (pol->core_share[count].status != 1)
223 power_manager_scale_core_max(
224 pol->core_share[count].pcpu);
226 } else if (diff >= (pol->pkt.traffic_policy.avg_max_packet_thresh)) {
227 for (count = 0; count < pol->pkt.num_vcpu; count++) {
228 if (pol->core_share[count].status != 1)
229 power_manager_scale_core_med(
230 pol->core_share[count].pcpu);
232 } else if (diff < (pol->pkt.traffic_policy.avg_max_packet_thresh)) {
233 for (count = 0; count < pol->pkt.num_vcpu; count++) {
234 if (pol->core_share[count].status != 1)
235 power_manager_scale_core_min(
236 pol->core_share[count].pcpu);
242 apply_time_profile(struct policy *pol)
248 char time_string[40];
250 /* Obtain the time of day, and convert it to a tm struct. */
251 gettimeofday(&tv, NULL);
252 ptm = localtime(&tv.tv_sec);
253 /* Format the date and time, down to a single second. */
254 strftime(time_string, sizeof(time_string), "%Y-%m-%d %H:%M:%S", ptm);
256 for (x = 0; x < HOURS; x++) {
258 if (ptm->tm_hour == pol->pkt.timer_policy.busy_hours[x]) {
259 for (count = 0; count < pol->pkt.num_vcpu; count++) {
260 if (pol->core_share[count].status != 1) {
261 power_manager_scale_core_max(
262 pol->core_share[count].pcpu);
263 RTE_LOG(INFO, CHANNEL_MONITOR,
264 "Scaling up core %d to max\n",
265 pol->core_share[count].pcpu);
269 } else if (ptm->tm_hour ==
270 pol->pkt.timer_policy.quiet_hours[x]) {
271 for (count = 0; count < pol->pkt.num_vcpu; count++) {
272 if (pol->core_share[count].status != 1) {
273 power_manager_scale_core_min(
274 pol->core_share[count].pcpu);
275 RTE_LOG(INFO, CHANNEL_MONITOR,
276 "Scaling down core %d to min\n",
277 pol->core_share[count].pcpu);
281 } else if (ptm->tm_hour ==
282 pol->pkt.timer_policy.hours_to_use_traffic_profile[x]) {
283 apply_traffic_profile(pol);
290 apply_workload_profile(struct policy *pol)
295 if (pol->pkt.workload == HIGH) {
296 for (count = 0; count < pol->pkt.num_vcpu; count++) {
297 if (pol->core_share[count].status != 1)
298 power_manager_scale_core_max(
299 pol->core_share[count].pcpu);
301 } else if (pol->pkt.workload == MEDIUM) {
302 for (count = 0; count < pol->pkt.num_vcpu; count++) {
303 if (pol->core_share[count].status != 1)
304 power_manager_scale_core_med(
305 pol->core_share[count].pcpu);
307 } else if (pol->pkt.workload == LOW) {
308 for (count = 0; count < pol->pkt.num_vcpu; count++) {
309 if (pol->core_share[count].status != 1)
310 power_manager_scale_core_min(
311 pol->core_share[count].pcpu);
317 apply_policy(struct policy *pol)
320 struct channel_packet *pkt = &pol->pkt;
322 /*Check policy to use*/
323 if (pkt->policy_to_use == TRAFFIC)
324 apply_traffic_profile(pol);
325 else if (pkt->policy_to_use == TIME)
326 apply_time_profile(pol);
327 else if (pkt->policy_to_use == WORKLOAD)
328 apply_workload_profile(pol);
333 process_request(struct channel_packet *pkt, struct channel_info *chan_info)
337 if (chan_info == NULL)
340 if (rte_atomic32_cmpset(&(chan_info->status), CHANNEL_MGR_CHANNEL_CONNECTED,
341 CHANNEL_MGR_CHANNEL_PROCESSING) == 0)
344 if (pkt->command == CPU_POWER) {
345 core_mask = get_pcpus_mask(chan_info, pkt->resource_id);
346 if (core_mask == 0) {
347 RTE_LOG(ERR, CHANNEL_MONITOR, "Error get physical CPU mask for "
348 "channel '%s' using vCPU(%u)\n", chan_info->channel_path,
349 (unsigned)pkt->unit);
352 if (__builtin_popcountll(core_mask) == 1) {
354 unsigned core_num = __builtin_ffsll(core_mask) - 1;
357 case(CPU_POWER_SCALE_MIN):
358 power_manager_scale_core_min(core_num);
360 case(CPU_POWER_SCALE_MAX):
361 power_manager_scale_core_max(core_num);
363 case(CPU_POWER_SCALE_DOWN):
364 power_manager_scale_core_down(core_num);
366 case(CPU_POWER_SCALE_UP):
367 power_manager_scale_core_up(core_num);
369 case(CPU_POWER_ENABLE_TURBO):
370 power_manager_enable_turbo_core(core_num);
372 case(CPU_POWER_DISABLE_TURBO):
373 power_manager_disable_turbo_core(core_num);
380 case(CPU_POWER_SCALE_MIN):
381 power_manager_scale_mask_min(core_mask);
383 case(CPU_POWER_SCALE_MAX):
384 power_manager_scale_mask_max(core_mask);
386 case(CPU_POWER_SCALE_DOWN):
387 power_manager_scale_mask_down(core_mask);
389 case(CPU_POWER_SCALE_UP):
390 power_manager_scale_mask_up(core_mask);
392 case(CPU_POWER_ENABLE_TURBO):
393 power_manager_enable_turbo_mask(core_mask);
395 case(CPU_POWER_DISABLE_TURBO):
396 power_manager_disable_turbo_mask(core_mask);
405 if (pkt->command == PKT_POLICY) {
406 RTE_LOG(INFO, CHANNEL_MONITOR, "\nProcessing Policy request from Guest\n");
411 /* Return is not checked as channel status may have been set to DISABLED
412 * from management thread
414 rte_atomic32_cmpset(&(chan_info->status), CHANNEL_MGR_CHANNEL_PROCESSING,
415 CHANNEL_MGR_CHANNEL_CONNECTED);
421 add_channel_to_monitor(struct channel_info **chan_info)
423 struct channel_info *info = *chan_info;
424 struct epoll_event event;
426 event.events = EPOLLIN;
427 event.data.ptr = info;
428 if (epoll_ctl(global_event_fd, EPOLL_CTL_ADD, info->fd, &event) < 0) {
429 RTE_LOG(ERR, CHANNEL_MONITOR, "Unable to add channel '%s' "
430 "to epoll\n", info->channel_path);
437 remove_channel_from_monitor(struct channel_info *chan_info)
439 if (epoll_ctl(global_event_fd, EPOLL_CTL_DEL, chan_info->fd, NULL) < 0) {
440 RTE_LOG(ERR, CHANNEL_MONITOR, "Unable to remove channel '%s' "
441 "from epoll\n", chan_info->channel_path);
448 channel_monitor_init(void)
450 global_event_fd = epoll_create1(0);
451 if (global_event_fd == 0) {
452 RTE_LOG(ERR, CHANNEL_MONITOR, "Error creating epoll context with "
453 "error %s\n", strerror(errno));
456 global_events_list = rte_malloc("epoll_events", sizeof(*global_events_list)
457 * MAX_EVENTS, RTE_CACHE_LINE_SIZE);
458 if (global_events_list == NULL) {
459 RTE_LOG(ERR, CHANNEL_MONITOR, "Unable to rte_malloc for "
467 run_channel_monitor(void)
472 n_events = epoll_wait(global_event_fd, global_events_list,
476 for (i = 0; i < n_events; i++) {
477 struct channel_info *chan_info = (struct channel_info *)
478 global_events_list[i].data.ptr;
479 if ((global_events_list[i].events & EPOLLERR) ||
480 (global_events_list[i].events & EPOLLHUP)) {
481 RTE_LOG(DEBUG, CHANNEL_MONITOR, "Remote closed connection for "
483 chan_info->channel_path);
484 remove_channel(&chan_info);
487 if (global_events_list[i].events & EPOLLIN) {
489 int n_bytes, err = 0;
490 struct channel_packet pkt;
492 int buffer_len = sizeof(pkt);
494 while (buffer_len > 0) {
495 n_bytes = read(chan_info->fd,
497 if (n_bytes == buffer_len)
501 RTE_LOG(DEBUG, CHANNEL_MONITOR,
503 "channel '%s' read: %s\n",
504 chan_info->channel_path,
506 remove_channel(&chan_info);
509 buffer = (char *)buffer + n_bytes;
510 buffer_len -= n_bytes;
513 process_request(&pkt, chan_info);
516 rte_delay_us(time_period_ms*1000);
520 for (j = 0; j < MAX_VMS; j++) {
521 if (policies[j].enabled == 1)
522 apply_policy(&policies[j]);