From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 9B90FA0A0C; Thu, 15 Jul 2021 17:56:53 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 609624014D; Thu, 15 Jul 2021 17:56:53 +0200 (CEST) Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) by mails.dpdk.org (Postfix) with ESMTP id 8F15340143 for ; Thu, 15 Jul 2021 17:56:50 +0200 (CEST) X-IronPort-AV: E=McAfee;i="6200,9189,10046"; a="190255186" X-IronPort-AV: E=Sophos;i="5.84,242,1620716400"; d="scan'208";a="190255186" Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 15 Jul 2021 08:56:34 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.84,242,1620716400"; d="scan'208";a="489491685" Received: from silpixa00400900.ir.intel.com ([10.243.22.130]) by fmsmga004.fm.intel.com with ESMTP; 15 Jul 2021 08:56:32 -0700 From: Harneet Singh To: dts@dpdk.org Cc: Harneet Singh Date: Thu, 15 Jul 2021 15:56:30 +0000 Message-Id: <20210715155630.944051-1-harneet.singh@intel.com> X-Mailer: git-send-email 2.25.1 MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Subject: [dts] [PATCH] [PATCH]tests/power_brach_ratio: refactor power test X-BeenThere: dts@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: test suite reviews and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dts-bounces@dpdk.org Sender: "dts" This patch will make the test run on host instead of vm. Since vm is not required all vm code is removed. before test was comparing min max freq values to P1 which was not what we wanted, also the logical operator used didn't allow for some variance and forced to be exact freq number. So we fixed that by comparing current freq value of the core to P1 while in traffic and Logical operator have been changed to allow some variance when comparing with P1 Some addition to both .cfg and .py value for clear debugging example you can specify the range(from to) for vm power mgr and testpmd, also you can specify which exact core you want to check for test. Signed-off-by: Harneet Singh --- conf/power_branch_ratio.cfg | 4 + test_plans/power_branch_ratio_test_plan.rst | 133 ++------- tests/TestSuite_power_branch_ratio.py | 284 +++++--------------- 3 files changed, 94 insertions(+), 327 deletions(-) diff --git a/conf/power_branch_ratio.cfg b/conf/power_branch_ratio.cfg index d3499ffe..fd4a9b0e 100644 --- a/conf/power_branch_ratio.cfg +++ b/conf/power_branch_ratio.cfg @@ -31,3 +31,7 @@ login = [suite] frame_size = 1024 check_ratio = 0.3 +from_core = 1 +to_core = 3 +check_core = 2 +testpmd_cores = 1, 2 diff --git a/test_plans/power_branch_ratio_test_plan.rst b/test_plans/power_branch_ratio_test_plan.rst index e9a4a693..a3c208af 100644 --- a/test_plans/power_branch_ratio_test_plan.rst +++ b/test_plans/power_branch_ratio_test_plan.rst @@ -50,129 +50,36 @@ Prepare work 5. Set CONFIG_RTE_LIBRTE_POWER_DEBUG=y CONFIG_RTE_LIBRTE_POWER=y in /config/common_base file. 6. modprobe msr module to let the application can get the CPU HW info. 7. Let user space can control the CPU frequency:: + cpupower frequency-set -g userspace - cpupower frequency-set -g userspace +sys_min=/sys/devices/system/cpu/cpu2/cpufreq/cpuinfo_min_freq +no_turbo_max=$(rdmsr -p 2 0x0CE -f 15:8 -d)00000 -8. Prepare a valid VM using libvirt, 8 virtio-serial channel should be add as -configuration channel, vCPU and physical CPU mapping table should be configured. -The configuration part in libvirt is following:: - - - - - - - - - - - - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - ak - - -
- - - - -
- - - - -
- - - -sys_min=/sys/devices/system/cpu/cpu{}/cpufreq/cpuinfo_min_freq -sys_max=/sys/devices/system/cpu/cpu{}/cpufreq/cpuinfo_max_freq - -no_turbo_max=$(rdmsr -p 1 0x0CE -f 15:8 -d)00000 - -cur_min=sys/devices/system/cpu/cpu{}/cpufreq/scaling_min_freq -cur_max=sys/devices/system/cpu/cpu{}/cpufreq/scaling_max_freq - -Test Case 1 : Basic Branch-Ratio Test based on one NIC pass-through into VM Scenario -==================================================================================== -1. Launch VM by using libvirt, one NIC should be configured as PCI -pass-throughput to the VM:: - - virsh start [VM name] - -2. Launch VM power manager sample on the host to monitor the channel from VM:: - - ./examples/vm_power_manager/build/vm_power_mgr -l 12-14 -n 4 --no-pci - - >add_vm [vm name] - >add_channels [vm name] all - >set_channel_status [vm name] all enabled - >show_vm [vm name] - -3. In the VM, launch guest_vm_power_mgr to set and send the power manager policy -to the host power sample, the policy is set to BRANCH_RATIO, the default -BRANCH_RATIO threshold is 0.25:: - - ./examples/vm_power_manager/guest_cli/build/guest_vm_power_mgr -c 0xff -n 4 -m 1024 --no-pci --file-prefix=yaolei -- --vm-name=[vm name] --policy=BRANCH_RATIO --vcpu-list=0-7 - > send_policy now - -4. Bind one NIC to DPDK driver in VM, launch testpmd with fwd io mode:: - - ./x86_64-native-linuxapp-gcc/app/testpmd -l 0-1 -n 4 -m 1024 --file-prefix=test2 -- -i +Test Case 1 : Set Branch-Ratio Test Rate by User ==================================================================================== +1. Launch VM power manager sample on the host to run branch monitor. +./x86_64-native-linuxapp-gcc/examples/dpdk-vm_power_manager -v -c 0xe -n 1 -m 1024 --no-pci -- --core-branch-ratio=1-3:0.3 + +2. Launch testpmd with fwd io mode:: +./x86_64-native-linuxapp-gcc/app/dpdk-testpmd -v -c 0x6 -n 1 -m 1024 --file-prefix=vmpower2 -- -i > start -5. Inject packet with packet generator to the NIC, with line rate(For example), +3. Inject packet with packet generator to the NIC, with line rate, check the branch ratio and the related CPU frequency, in this case, the -core 1 will be used by testpmd as worker core, branch ratio will be shown as +core 2 will be used by testpmd as worker core, branch ratio will be shown as following in vm_power_mgr's log output:: - 1: 0.0048 {250065} {20001} 0: 0.0307 {35782} {20000} 1: 0.0042 {259798} {0} 1: 0.0045 {242642} {20001} -6. [Check Point]Inject packets with packet generator with Line Rate(10G), check -the core 1 frequency use following cmd, The Frequency reported should be at the +The above values in order are core number, ratio measured , # of branches, number of polls. + +4. [Check Point]Inject packets with packet generator with Line Rate(10G), check +the core 2 frequency use following cmd, The Frequency reported should be at the highest frequency:: - - [no_turbo_max]: cur_min=cur_max=no_turbo_max - cat /sys/devices/system/cpu/cpu2/cpufreq/cpuinfo_cur_freq - -7. [Check Point]Stopped the traffic from packet generator. Check the core 1 +cat /sys/devices/system/cpu/cpu2/cpufreq/scaling_cur_freq +[no_turbo_max]: cur_freq >= no_turbo_max(P1) + +5. [Check Point]Stopped the traffic from packet generator. Check the core 2 frequency again, the Frequency reported should be:: - - [sys_min]:cur_min=cur_max=sys_min - - -Test Case 2: Set Branch-Ratio Rate by User -========================================== -The same as test case1, the only difference is at step2 2. Launch VM power -manager sample on the host to monitor the channel from VM, set the branch -ration at host side:: - - ./examples/vm_power_manager/build/vm_power_mgr -l 12-14 -n 4 -m 1024 --no-pci -- --branch-ratio=0.1 - +[sys_min]:cur_freq <= sys_min \ No newline at end of file diff --git a/tests/TestSuite_power_branch_ratio.py b/tests/TestSuite_power_branch_ratio.py index ad04b2f8..eff4d6f7 100644 --- a/tests/TestSuite_power_branch_ratio.py +++ b/tests/TestSuite_power_branch_ratio.py @@ -55,8 +55,6 @@ from test_case import TestCase class TestPowerBranchRatio(TestCase): BRANCH_RATIO = "BRANCH_RATIO" - vm_name = 'vm0' - vm_max_ch = 8 @property def target_dir(self): @@ -123,17 +121,17 @@ class TestPowerBranchRatio(TestCase): return outputs - def d_con(self, cmds): - return self.execute_cmds(cmds, name=self.dut.session.name) + def d_con(self, cmd): + _cmd = [cmd, '# ', 10] if isinstance(cmd, str) else cmd + return self.dut.send_expect(*_cmd) - def d_a_con(self, cmds): - return self.execute_cmds(cmds, name=self.dut.alt_session.name) - - def vm_con(self, cmds): - return self.execute_cmds(cmds, name=self.vm_dut.session.name) - - def vm_g_con(self, cmds): - return self.execute_cmds(cmds, name=self.guest_con_name) + def d_a_con(self, cmd): + _cmd = [cmd, '# ', 10] if isinstance(cmd, str) else cmd + return self.dut.alt_session.send_expect(*_cmd) + + def d_sys_con(self, cmd): + _cmd = [cmd, '# ', 10] if isinstance(cmd, str) else cmd + return self.alt_sys_session.send_expect(*_cmd) def get_pkt_len(self, pkt_type, frame_size=1024): headers_size = sum([HEADER_SIZE[x] for x in ['eth', 'ip', pkt_type]]) @@ -220,70 +218,6 @@ class TestPowerBranchRatio(TestCase): return result - def create_powermonitor_folder(self): - # create temporary folder for power monitor - cmd = 'mkdir -p {0}; chmod 777 {0}'.format(self.vm_log_dir) - self.d_a_con(cmd) - - def init_vms_params(self): - self.vcpu_map = self.vcpu_lst = self.vm = self.vm_dut = self.guest_session = None - self.vm_log_dir = '/tmp/powermonitor' - self.create_powermonitor_folder() - - def add_pf_device(self, pci_addr, vm_inst): - vm_params = { - 'driver': 'pci-assign', - 'driver': 'vfio', - 'opt_host': pci_addr, - 'guestpci': '0000:00:07.0'} - vm_inst.set_vm_device(**vm_params) - - def start_vm(self): - ''' - ''' - # set vm initialize parameters - self.init_vms_params() - # start vm - self.vm = LibvirtKvm(self.dut, self.vm_name, self.suite_name) - # pass pf to virtual machine - pci_addr = self.dut.get_port_pci(self.dut_ports[0]) - self.add_pf_device(pci_addr, self.vm) - # add channel - ch_name = 'virtio.serial.port.poweragent.{0}' - vm_path = os.path.join(self.vm_log_dir, '{0}.{1}') - for cnt in range(self.vm_max_ch): - channel = { - 'path': vm_path.format(self.vm_name, cnt), - 'name': ch_name.format(cnt)} - self.vm.add_vm_virtio_serial_channel(**channel) - # set vm default driver - self.vm.def_driver = 'igb_uio' - # boot up vm - self.vm_dut = self.vm.start() - self.is_vm_on = True - self.verify(self.vm_dut, "create vm_dut fail !") - self.add_console(self.vm_dut.session) - # get virtual machine cpu cores - self.vcpu_map = [int(core) for core in self.vm.get_vm_cpu()] - self.vcpu_lst = [int(item['core']) for item in self.vm_dut.cores] - - def close_vm(self): - ''' - ''' - if not self.is_vm_on: - return - if self.guest_session: - self.vm_dut.close_session(self.guest_session) - self.vm.stop() - self.vm = None - self.is_vm_on = False - self.dut.virt_exit() - cmd_fmt = 'virsh {0} {1} > /dev/null 2>&1'.format - cmds = [ - [cmd_fmt('shutdown', self.vm_name), '# '], - [cmd_fmt('undefine', self.vm_name), '# '], ] - self.d_a_con(cmds) - @property def compile_switch(self): sw_table = [ @@ -354,77 +288,29 @@ class TestPowerBranchRatio(TestCase): 'memory_size': 1024, }) prompt = 'vmpower>' option = sub_option + \ - (' -- --core-branch-ratio={}'.format(self.branch_ratio) \ + (' -- --core-branch-ratio={0}-{1}:{2}'.format(self.from_core, self.to_core, self.branch_ratio) if self.branch_ratio else '') cmd = [' '.join([self.vm_power_mgr, option]), prompt, 50] self.d_con(cmd) self.is_mgr_on = True - - def set_vm_power_mgr(self): - vm_name = self.vm_name - cmds = [ - "add_vm %s" % vm_name, - "add_channels %s all" % vm_name, - 'set_channel_status %s all enabled' % vm_name, - "show_vm %s" % vm_name] - prompt = 'vmpower>' - self.d_con([[cmd, prompt] for cmd in cmds]) - + def close_vm_power_mgr(self): if not self.is_mgr_on: return self.d_con(['quit', '# ', 30]) self.is_mgr_on = False - def init_guest_mgr(self): - name = 'vm_power_manager/guest_cli' - self.guest_cli = self.prepare_binary(name, host_crb=self.vm_dut) - self.guest_con_name = \ - '_'.join([self.vm_dut.NAME, name.replace('/', '-')]) - self.guest_session = self.vm_dut.create_session(self.guest_con_name) - self.add_console(self.guest_session) + def add_alternative_session_to_dut(self): + self.alt_sys_session = self.dut.create_session("alt_sys_session") - def start_guest_mgr(self): - prompt = r"vmpower\(guest\)>" - option = ( - '-v ' - '-c {core_mask} ' - '-n {memory_channel} ' - '-m {memory_size} ' - '--no-pci ' - '--file-prefix={file_prefix} ' - '-- ' - '--vm-name={vm_name} ' - '--policy={policy} ' - '--vcpu-list={vpus} ').format(**{ - 'core_mask': '0xff', - 'memory_channel': self.vm_dut.get_memory_channels(), - 'memory_size': 1024, - 'policy': self.BRANCH_RATIO, - 'file_prefix': 'vmpower1', - 'vm_name': self.vm_name, - 'vpus': ','.join( - [str(index) for index in self.vcpu_lst]), - }) - guest_cmd = ' '.join([self.guest_cli, option]) - self.vm_g_con([guest_cmd, prompt, 120]) - self.is_guest_on = True - - def send_policy_on_guest_mgr(self): - self.vm_g_con(['send_policy now', r"vmpower\(guest\)>", 20]) - - def close_guest_mgr(self): - if not self.is_guest_on: - return - self.vm_g_con("quit") - self.is_guest_on = False - - def init_vm_testpmd(self): - self.vm_testpmd = os.path.join(self.target_dir, + def init_testpmd(self): + self.testpmd = os.path.join(self.target_dir, self.dut.apps_name['test-pmd']) - def start_vm_testpmd(self): - cores = [0, 1] + def start_testpmd(self): + cores = [] + for core in self.testpmd_cores: + cores.append(core) core_mask = dts_create_mask(cores) option = ( '-v ' @@ -434,22 +320,22 @@ class TestPowerBranchRatio(TestCase): '--file-prefix={file-prefix} ' '-- -i ').format(**{ 'core_mask': core_mask, - 'mem_channel': self.vm_dut.get_memory_channels(), + 'mem_channel': self.dut.get_memory_channels(), 'memsize': 1024, 'file-prefix': 'vmpower2', }) - cmd = ' '.join([self.vm_testpmd, option]) - self.vm_con([cmd, "testpmd> ", 120]) + cmd = ' '.join([self.testpmd, option]) + self.d_a_con([cmd, "testpmd> ", 120]) self.is_pmd_on = True - def set_vm_testpmd(self): + def set_testpmd(self): cmd = 'start' - self.vm_con([cmd, "testpmd> ", 15]) + self.d_a_con([cmd, "testpmd> ", 15]) - def close_vm_testpmd(self): + def close_testpmd(self): if not self.is_pmd_on: return - self.vm_con(['quit', '# ', 15]) + self.d_a_con(['quit', '# ', 15]) self.is_pmd_on = False def get_sys_power_driver(self): @@ -463,31 +349,17 @@ class TestPowerBranchRatio(TestCase): def query_cpu_freq(self): cmd = ';'.join([ - "cat /sys/devices/system/cpu/cpu{0}/cpufreq/scaling_min_freq", - "cat /sys/devices/system/cpu/cpu{0}/cpufreq/scaling_max_freq" + "cat /sys/devices/system/cpu/cpu{0}/cpufreq/scaling_cur_freq" ]).format(self.check_core) - output = self.d_a_con(cmd) + output = self.d_sys_con(cmd) if not output: - self.scaling_min_freq, self.scaling_max_freq = 0, 0 + self.scaling_cur_freq = 0 else: - values = [int(item) for item in output.splitlines()] - self.scaling_min_freq, self.scaling_max_freq = values - - def get_core_scaling_max_freq(self, core_index): - cpu_attr = '/sys/devices/system/cpu/cpu{0}/cpufreq/scaling_max_freq' - cmd = 'cat ' + cpu_attr.format(core_index) - output = self.d_a_con(cmd) - return int(output) - - def get_core_scaling_min_freq(self, core_index): - cpu_attr = '/sys/devices/system/cpu/cpu{0}/cpufreq/scaling_min_freq' - cmd = 'cat ' + cpu_attr.format(core_index) - output = self.d_a_con(cmd) - return int(output) + self.scaling_cur_freq = round(int(output)) def get_no_turbo_max(self): cmd = 'rdmsr -p {} 0x0CE -f 15:8 -d'.format(self.check_core) - output = self.d_a_con(cmd) + output = self.d_sys_con(cmd) freq = output.strip() + '00000' return int(freq) @@ -517,42 +389,33 @@ class TestPowerBranchRatio(TestCase): def run_test_pre(self): # boot up binary processes self.start_vm_power_mgr() - # set binary process command - self.set_vm_power_mgr() - # boot up binary processes - self.start_guest_mgr() - # set binary process command - self.send_policy_on_guest_mgr() # boot up binary processes - self.start_vm_testpmd() + self.start_testpmd() # set binary process command - self.set_vm_testpmd() + self.set_testpmd() + def run_test_post(self): # close all binary processes - self.close_vm_testpmd() - self.close_guest_mgr() + self.close_testpmd() self.close_vm_power_mgr() def check_core_freq_in_traffic(self, core_index): ''' check the cores frequency when running traffic - highest frequency[no_turbo_max]: cur_min=cur_max=no_turbo_max + highest frequency[no_turbo_max]: expected_freq(P1) <= cur_freq ''' expected_freq = self.get_no_turbo_max() - msg = 'max freq is failed to get.' - self.verify(self.scaling_max_freq, msg) - msg = 'max freq is not the same as highest frequency <{0}>' - self.verify(expected_freq == self.scaling_max_freq, - msg.format(expected_freq)) - msg = 'min freq is failed to get.' - self.verify(self.scaling_min_freq, msg) - msg = 'min freq is not the same as highest frequency <{0}>' - self.verify(expected_freq == self.scaling_min_freq, - msg.format(expected_freq)) + msg = 'failed to get cur freq.' + self.verify(self.scaling_cur_freq, msg) + msg = 'cur freq <{0}> is lower than expected freq <{1}>' + self.verify(expected_freq <= self.scaling_cur_freq, + msg.format(self.scaling_cur_freq ,expected_freq)) msg = "core <{0}> action is ok in traffic".format(core_index) self.logger.info(msg) - + displayFreqData = "Freqs in Traffic : Check Core Freq {0} >= Expected Freq {1}".format(self.scaling_cur_freq, expected_freq) + self.logger.info(displayFreqData) + def check_vm_power_mgr_output(self): ''' check the branch miss ration and the related CPU frequency, the core @@ -569,20 +432,22 @@ class TestPowerBranchRatio(TestCase): msg = "branch ratio output is ok" self.logger.info(msg) - def check_dut_core_freq(self, core_index, ref_freq_name): - ''' - Check the core frequency, the frequency reported should be:: - [sys_min]: cur_min=cur_max=sys_min - ''' - expected_freq = self.cpu_info.get(core_index, {}).get(ref_freq_name) - max_freq = self.get_core_scaling_max_freq(core_index) - min_freq = self.get_core_scaling_min_freq(core_index) - msg = 'max freq<{0}>/min_freq<{1}>/expected freq<{2}> are not the same' - self.verify( - max_freq == min_freq and max_freq == expected_freq, - msg.format(max_freq, min_freq, expected_freq)) - msg = "core <{0}> action is ok after traffic stop".format(core_index) - self.logger.info(msg) + def check_core_freq_no_traffic(self, core_index, ref_freq_name): + ''' + Check the core frequency, the frequency reported should be:: + cur_freq <= sys_min + ''' + expected_freq = self.cpu_info.get(core_index, {}).get(ref_freq_name) + self.query_cpu_freq() + time.sleep(1) + msg = 'cur freq<{0}> is higher than /expected freq<{1}> in no traffic' + self.verify( + self.scaling_cur_freq <= expected_freq, + msg.format(self.scaling_cur_freq, expected_freq)) + msg = "core <{0}> action is ok after traffic stop".format(core_index) + self.logger.info(msg) + displayFreqData = "Freqs in NO Traffic: Check Core Freq {0} <= Expected Freq {1}".format(self.scaling_cur_freq, expected_freq) + self.logger.info(displayFreqData) def verify_branch_ratio(self): except_content = None @@ -598,7 +463,7 @@ class TestPowerBranchRatio(TestCase): # check test result self.check_core_freq_in_traffic(self.check_core) self.check_vm_power_mgr_output() - self.check_dut_core_freq(self.check_core, 'cpuinfo_min_freq') + self.check_core_freq_no_traffic(self.check_core, 'cpuinfo_min_freq') except Exception as e: self.logger.error(traceback.format_exc()) except_content = e @@ -626,8 +491,7 @@ class TestPowerBranchRatio(TestCase): self.verify(status, msg) def init_params(self): - self.is_mgr_on = self.is_guest_on = self.is_pmd_on = \ - self.is_vm_on = None + self.is_mgr_on = self.is_pmd_on = None self.ext_con = {} # set branch ratio test value self.branch_ratio = None @@ -640,16 +504,17 @@ class TestPowerBranchRatio(TestCase): self.d_a_con('cpupower frequency-set -g userspace > /dev/null 2>&1') # compile self.preset_compilation() - # boot up vm - self.start_vm() # init binary self.init_vm_power_mgr() - self.init_vm_testpmd() - self.init_guest_mgr() + self.init_testpmd() + self.add_alternative_session_to_dut() test_content = self.get_suite_cfg() self.frame_size = test_content.get('frame_size') or 1024 self.check_ratio = test_content.get('check_ratio') or 0.1 - self.check_core = self.vcpu_map[1] + self.from_core = test_content.get('from_core') + self.to_core = test_content.get('to_core') + self.check_core = test_content.get('check_core') + self.testpmd_cores = test_content.get('testpmd_cores') msg = "select dut core {} as check core".format(self.check_core) self.logger.info(msg) # @@ -672,8 +537,7 @@ class TestPowerBranchRatio(TestCase): """ Run after each test suite. """ - with self.restore_environment(): - self.close_vm() + self.restore_environment() def set_up(self): """ @@ -685,16 +549,8 @@ class TestPowerBranchRatio(TestCase): """ Run after each test case. """ - self.vm_dut.kill_all() self.dut.kill_all() - def test_perf_basic_branch_ratio(self): - """ - Basic branch-ratio test based on one NIC pass-through into VM scenario - """ - self.branch_ratio = None - self.verify_branch_ratio() - def test_perf_set_branch_ratio_rate_by_user(self): """ Set Branch-Ratio Rate by User -- 2.25.1 -------------------------------------------------------------- Intel Research and Development Ireland Limited Registered in Ireland Registered Office: Collinstown Industrial Park, Leixlip, County Kildare Registered Number: 308263 This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). Any review or distribution by others is strictly prohibited. If you are not the intended recipient, please contact the sender and delete all copies.