196a1be4fSAniruddha Paul /* 296a1be4fSAniruddha Paul * Copyright (c) 2020 The Linux Foundation. All rights reserved. 3*3cbfba98SJeff Johnson * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. 496a1be4fSAniruddha Paul * 596a1be4fSAniruddha Paul * Permission to use, copy, modify, and/or distribute this software for 696a1be4fSAniruddha Paul * any purpose with or without fee is hereby granted, provided that the 796a1be4fSAniruddha Paul * above copyright notice and this permission notice appear in all 896a1be4fSAniruddha Paul * copies. 996a1be4fSAniruddha Paul * 1096a1be4fSAniruddha Paul * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 1196a1be4fSAniruddha Paul * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 1296a1be4fSAniruddha Paul * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 1396a1be4fSAniruddha Paul * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 1496a1be4fSAniruddha Paul * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 1596a1be4fSAniruddha Paul * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 1696a1be4fSAniruddha Paul * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 1796a1be4fSAniruddha Paul * PERFORMANCE OF THIS SOFTWARE. 1896a1be4fSAniruddha Paul */ 1996a1be4fSAniruddha Paul 2096a1be4fSAniruddha Paul #include <qdf_util.h> 2196a1be4fSAniruddha Paul #include <qdf_mem.h> 2296a1be4fSAniruddha Paul #include <cdp_txrx_hist_struct.h> 2396a1be4fSAniruddha Paul #include "dp_hist.h" 2496a1be4fSAniruddha Paul 2594c2c627SRipan Deuri #ifndef WLAN_CONFIG_TX_DELAY 2696a1be4fSAniruddha Paul /* 27ebfbc0d9SJeff Johnson * dp_hist_sw_enq_dbucket: Software enqueue delay bucket in ms 2896a1be4fSAniruddha Paul * @index_0 = 0_1 ms 2996a1be4fSAniruddha Paul * @index_1 = 1_2 ms 3096a1be4fSAniruddha Paul * @index_2 = 2_3 ms 3196a1be4fSAniruddha Paul * @index_3 = 3_4 ms 3296a1be4fSAniruddha Paul * @index_4 = 4_5 ms 3396a1be4fSAniruddha Paul * @index_5 = 5_6 ms 3496a1be4fSAniruddha Paul * @index_6 = 6_7 ms 3596a1be4fSAniruddha Paul * @index_7 = 7_8 ms 3696a1be4fSAniruddha Paul * @index_8 = 8_9 ms 37083ffa02SParikshit Gune * @index_9 = 9_10 ms 38083ffa02SParikshit Gune * @index_10 = 10_11 ms 39083ffa02SParikshit Gune * @index_11 = 11_12 ms 40083ffa02SParikshit Gune * @index_12 = 12+ ms 4196a1be4fSAniruddha Paul */ 4296a1be4fSAniruddha Paul static uint16_t dp_hist_sw_enq_dbucket[CDP_HIST_BUCKET_MAX] = { 43083ffa02SParikshit Gune 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; 4496a1be4fSAniruddha Paul 4596a1be4fSAniruddha Paul /* 4696a1be4fSAniruddha Paul * cdp_hist_fw2hw_dbucket: HW enqueue to Completion Delay 4796a1be4fSAniruddha Paul * @index_0 = 0_10 ms 4896a1be4fSAniruddha Paul * @index_1 = 10_20 ms 4996a1be4fSAniruddha Paul * @index_2 = 20_30ms 5096a1be4fSAniruddha Paul * @index_3 = 30_40 ms 5196a1be4fSAniruddha Paul * @index_4 = 40_50 ms 5296a1be4fSAniruddha Paul * @index_5 = 50_60 ms 5396a1be4fSAniruddha Paul * @index_6 = 60_70 ms 5496a1be4fSAniruddha Paul * @index_7 = 70_80 ms 5596a1be4fSAniruddha Paul * @index_8 = 80_90 ms 56083ffa02SParikshit Gune * @index_9 = 90_100 ms 57083ffa02SParikshit Gune * @index_10 = 100_250 ms 58083ffa02SParikshit Gune * @index_11 = 250_500 ms 59083ffa02SParikshit Gune * @index_12 = 500+ ms 6096a1be4fSAniruddha Paul */ 6196a1be4fSAniruddha Paul static uint16_t dp_hist_fw2hw_dbucket[CDP_HIST_BUCKET_MAX] = { 62083ffa02SParikshit Gune 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 250, 500}; 6394c2c627SRipan Deuri #else 6494c2c627SRipan Deuri /* 65ebfbc0d9SJeff Johnson * dp_hist_sw_enq_dbucket: Software enqueue delay bucket in us 6694c2c627SRipan Deuri * @index_0 = 0_250 us 6794c2c627SRipan Deuri * @index_1 = 250_500 us 6894c2c627SRipan Deuri * @index_2 = 500_750 us 6994c2c627SRipan Deuri * @index_3 = 750_1000 us 7094c2c627SRipan Deuri * @index_4 = 1000_1500 us 7194c2c627SRipan Deuri * @index_5 = 1500_2000 us 7294c2c627SRipan Deuri * @index_6 = 2000_2500 us 7394c2c627SRipan Deuri * @index_7 = 2500_5000 us 7494c2c627SRipan Deuri * @index_8 = 5000_6000 us 7594c2c627SRipan Deuri * @index_9 = 6000_7000 us 7694c2c627SRipan Deuri * @index_10 = 7000_8000 us 7794c2c627SRipan Deuri * @index_11 = 8000_9000 us 7894c2c627SRipan Deuri * @index_12 = 9000+ us 7994c2c627SRipan Deuri */ 8094c2c627SRipan Deuri static uint16_t dp_hist_sw_enq_dbucket[CDP_HIST_BUCKET_MAX] = { 8194c2c627SRipan Deuri 0, 250, 500, 750, 1000, 1500, 2000, 2500, 5000, 6000, 7000, 8000, 9000}; 8294c2c627SRipan Deuri 8394c2c627SRipan Deuri /* 8494c2c627SRipan Deuri * cdp_hist_fw2hw_dbucket: HW enqueue to Completion Delay in us 8594c2c627SRipan Deuri * @index_0 = 0_250 us 8694c2c627SRipan Deuri * @index_1 = 250_500 us 8794c2c627SRipan Deuri * @index_2 = 500_750 us 8894c2c627SRipan Deuri * @index_3 = 750_1000 us 8994c2c627SRipan Deuri * @index_4 = 1000_1500 us 9094c2c627SRipan Deuri * @index_5 = 1500_2000 us 9194c2c627SRipan Deuri * @index_6 = 2000_2500 us 9294c2c627SRipan Deuri * @index_7 = 2500_5000 us 9394c2c627SRipan Deuri * @index_8 = 5000_6000 us 9494c2c627SRipan Deuri * @index_9 = 6000_7000 us 9594c2c627SRipan Deuri * @index_10 = 7000_8000 us 9694c2c627SRipan Deuri * @index_11 = 8000_9000 us 9794c2c627SRipan Deuri * @index_12 = 9000+ us 9894c2c627SRipan Deuri */ 9994c2c627SRipan Deuri 10094c2c627SRipan Deuri static uint16_t dp_hist_fw2hw_dbucket[CDP_HIST_BUCKET_MAX] = { 10194c2c627SRipan Deuri 0, 250, 500, 750, 1000, 1500, 2000, 2500, 5000, 6000, 7000, 8000, 9000}; 10294c2c627SRipan Deuri #endif 10396a1be4fSAniruddha Paul 10496a1be4fSAniruddha Paul /* 10596a1be4fSAniruddha Paul * dp_hist_reap2stack_bucket: Reap to stack bucket 10696a1be4fSAniruddha Paul * @index_0 = 0_5 ms 10796a1be4fSAniruddha Paul * @index_1 = 5_10 ms 10896a1be4fSAniruddha Paul * @index_2 = 10_15 ms 10996a1be4fSAniruddha Paul * @index_3 = 15_20 ms 11096a1be4fSAniruddha Paul * @index_4 = 20_25 ms 11196a1be4fSAniruddha Paul * @index_5 = 25_30 ms 11296a1be4fSAniruddha Paul * @index_6 = 30_35 ms 11396a1be4fSAniruddha Paul * @index_7 = 35_40 ms 11496a1be4fSAniruddha Paul * @index_8 = 40_45 ms 115083ffa02SParikshit Gune * @index_9 = 46_50 ms 116083ffa02SParikshit Gune * @index_10 = 51_55 ms 117083ffa02SParikshit Gune * @index_11 = 56_60 ms 118083ffa02SParikshit Gune * @index_12 = 60+ ms 11996a1be4fSAniruddha Paul */ 12096a1be4fSAniruddha Paul static uint16_t dp_hist_reap2stack_bucket[CDP_HIST_BUCKET_MAX] = { 121083ffa02SParikshit Gune 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60}; 12296a1be4fSAniruddha Paul 12396a1be4fSAniruddha Paul /* 12473c7a4f2SDebasis Das * dp_hist_hw_tx_comp_dbucket: tx hw completion delay bucket in us 125ae12b7c4SRipan Deuri * @index_0 = 0_250 us 126ae12b7c4SRipan Deuri * @index_1 = 250_500 us 127ae12b7c4SRipan Deuri * @index_2 = 500_750 us 128ae12b7c4SRipan Deuri * @index_3 = 750_1000 us 129ae12b7c4SRipan Deuri * @index_4 = 1000_1500 us 130ae12b7c4SRipan Deuri * @index_5 = 1500_2000 us 131ae12b7c4SRipan Deuri * @index_6 = 2000_2500 us 132ae12b7c4SRipan Deuri * @index_7 = 2500_5000 us 133ae12b7c4SRipan Deuri * @index_8 = 5000_6000 us 134ae12b7c4SRipan Deuri * @index_9 = 6000_7000 us 135ae12b7c4SRipan Deuri * @index_10 = 7000_8000 us 136ae12b7c4SRipan Deuri * @index_11 = 8000_9000 us 137ae12b7c4SRipan Deuri * @index_12 = 9000+ us 138ae12b7c4SRipan Deuri */ 139ae12b7c4SRipan Deuri static uint16_t dp_hist_hw_tx_comp_dbucket[CDP_HIST_BUCKET_MAX] = { 140ae12b7c4SRipan Deuri 0, 250, 500, 750, 1000, 1500, 2000, 2500, 5000, 6000, 7000, 8000, 9000}; 141ae12b7c4SRipan Deuri 142ae12b7c4SRipan Deuri static const char *dp_hist_hw_tx_comp_dbucket_str[CDP_HIST_BUCKET_MAX + 1] = { 143ae12b7c4SRipan Deuri "0 to 250 us", "250 to 500 us", 144ae12b7c4SRipan Deuri "500 to 750 us", "750 to 1000 us", 145ae12b7c4SRipan Deuri "1000 to 1500 us", "1500 to 2000 us", 146ae12b7c4SRipan Deuri "2000 to 2500 us", "2500 to 5000 us", 147ae12b7c4SRipan Deuri "5000 to 6000 us", "6000 to 7000 ms", 148ae12b7c4SRipan Deuri "7000 to 8000 us", "8000 to 9000 us", "9000+ us" 149ae12b7c4SRipan Deuri }; 150ae12b7c4SRipan Deuri 151ae12b7c4SRipan Deuri const char *dp_hist_tx_hw_delay_str(uint8_t index) 152ae12b7c4SRipan Deuri { 153ae12b7c4SRipan Deuri if (index > CDP_HIST_BUCKET_MAX) 154ae12b7c4SRipan Deuri return "Invalid index"; 155ae12b7c4SRipan Deuri return dp_hist_hw_tx_comp_dbucket_str[index]; 156ae12b7c4SRipan Deuri } 157ae12b7c4SRipan Deuri 158ae12b7c4SRipan Deuri /* 15973c7a4f2SDebasis Das * dp_hist_delay_percentile_dbucket: tx hw completion delay bucket in delay 16073c7a4f2SDebasis Das * bound percentile 16173c7a4f2SDebasis Das * @index_0 = 0_10 16273c7a4f2SDebasis Das * @index_1 = 10_20 16373c7a4f2SDebasis Das * @index_2 = 20_30 16473c7a4f2SDebasis Das * @index_3 = 30_40 16573c7a4f2SDebasis Das * @index_4 = 40_50 16673c7a4f2SDebasis Das * @index_5 = 50_60 16773c7a4f2SDebasis Das * @index_6 = 60_70 16873c7a4f2SDebasis Das * @index_7 = 70_80 16973c7a4f2SDebasis Das * @index_8 = 80_100 17073c7a4f2SDebasis Das * @index_9 = 90_100 17173c7a4f2SDebasis Das * @index_10 = 100_150 17273c7a4f2SDebasis Das * @index_11 = 150_200 17373c7a4f2SDebasis Das * @index_12 = 200+ 17473c7a4f2SDebasis Das */ 17573c7a4f2SDebasis Das static uint16_t dp_hist_delay_percentile_dbucket[CDP_HIST_BUCKET_MAX] = { 17673c7a4f2SDebasis Das 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 150, 200}; 17773c7a4f2SDebasis Das 17873c7a4f2SDebasis Das static 17973c7a4f2SDebasis Das const char *dp_hist_delay_percentile_dbucket_str[CDP_HIST_BUCKET_MAX + 1] = { 18073c7a4f2SDebasis Das "0 to 10%", "10 to 20%", 18173c7a4f2SDebasis Das "20 to 30%", "30 to 40%", 18273c7a4f2SDebasis Das "40 to 50%", "50 to 60%", 18373c7a4f2SDebasis Das "60 to 70%", "70 to 80%", 18473c7a4f2SDebasis Das "80 to 90% ", "90 to 100%", 18573c7a4f2SDebasis Das "100 to 150% ", "150 to 200%", "200+%" 18673c7a4f2SDebasis Das }; 18773c7a4f2SDebasis Das 18873c7a4f2SDebasis Das const char *dp_hist_delay_percentile_str(uint8_t index) 18973c7a4f2SDebasis Das { 19073c7a4f2SDebasis Das if (index > CDP_HIST_BUCKET_MAX) 19173c7a4f2SDebasis Das return "Invalid index"; 19273c7a4f2SDebasis Das return dp_hist_delay_percentile_dbucket_str[index]; 19373c7a4f2SDebasis Das } 19473c7a4f2SDebasis Das 195*3cbfba98SJeff Johnson /** 196*3cbfba98SJeff Johnson * dp_hist_find_bucket_idx() - Find the bucket index 19796a1be4fSAniruddha Paul * @bucket_array: Bucket array 19896a1be4fSAniruddha Paul * @value: Frequency value 19996a1be4fSAniruddha Paul * 20096a1be4fSAniruddha Paul * Return: The bucket index 20196a1be4fSAniruddha Paul */ 20296a1be4fSAniruddha Paul static int dp_hist_find_bucket_idx(int16_t *bucket_array, int value) 20396a1be4fSAniruddha Paul { 20496a1be4fSAniruddha Paul uint8_t idx = CDP_HIST_BUCKET_0; 20596a1be4fSAniruddha Paul 20696a1be4fSAniruddha Paul for (; idx < (CDP_HIST_BUCKET_MAX - 1); idx++) { 20796a1be4fSAniruddha Paul if (value < bucket_array[idx + 1]) 20896a1be4fSAniruddha Paul break; 20996a1be4fSAniruddha Paul } 21096a1be4fSAniruddha Paul 21196a1be4fSAniruddha Paul return idx; 21296a1be4fSAniruddha Paul } 21396a1be4fSAniruddha Paul 214*3cbfba98SJeff Johnson /** 215*3cbfba98SJeff Johnson * dp_hist_fill_buckets() - Fill the histogram frequency buckets 21696a1be4fSAniruddha Paul * @hist_bucket: Histogram bukcets 21796a1be4fSAniruddha Paul * @value: Frequency value 21896a1be4fSAniruddha Paul * 21996a1be4fSAniruddha Paul * Return: void 22096a1be4fSAniruddha Paul */ 22196a1be4fSAniruddha Paul static void dp_hist_fill_buckets(struct cdp_hist_bucket *hist_bucket, int value) 22296a1be4fSAniruddha Paul { 22396a1be4fSAniruddha Paul enum cdp_hist_types hist_type; 22496a1be4fSAniruddha Paul int idx = CDP_HIST_BUCKET_MAX; 22596a1be4fSAniruddha Paul 22696a1be4fSAniruddha Paul if (qdf_unlikely(!hist_bucket)) 22796a1be4fSAniruddha Paul return; 22896a1be4fSAniruddha Paul 22996a1be4fSAniruddha Paul hist_type = hist_bucket->hist_type; 23096a1be4fSAniruddha Paul 23196a1be4fSAniruddha Paul /* Identify the bucket the bucket and update. */ 23296a1be4fSAniruddha Paul switch (hist_type) { 23396a1be4fSAniruddha Paul case CDP_HIST_TYPE_SW_ENQEUE_DELAY: 23496a1be4fSAniruddha Paul idx = dp_hist_find_bucket_idx(&dp_hist_sw_enq_dbucket[0], 23596a1be4fSAniruddha Paul value); 23696a1be4fSAniruddha Paul break; 23796a1be4fSAniruddha Paul case CDP_HIST_TYPE_HW_COMP_DELAY: 23896a1be4fSAniruddha Paul idx = dp_hist_find_bucket_idx(&dp_hist_fw2hw_dbucket[0], 23996a1be4fSAniruddha Paul value); 24096a1be4fSAniruddha Paul break; 24196a1be4fSAniruddha Paul case CDP_HIST_TYPE_REAP_STACK: 24296a1be4fSAniruddha Paul idx = dp_hist_find_bucket_idx( 24396a1be4fSAniruddha Paul &dp_hist_reap2stack_bucket[0], value); 24496a1be4fSAniruddha Paul break; 245ae12b7c4SRipan Deuri case CDP_HIST_TYPE_HW_TX_COMP_DELAY: 246ae12b7c4SRipan Deuri idx = dp_hist_find_bucket_idx( 247ae12b7c4SRipan Deuri &dp_hist_hw_tx_comp_dbucket[0], value); 248ae12b7c4SRipan Deuri break; 24973c7a4f2SDebasis Das case CDP_HIST_TYPE_DELAY_PERCENTILE: 25073c7a4f2SDebasis Das idx = dp_hist_find_bucket_idx( 25173c7a4f2SDebasis Das &dp_hist_delay_percentile_dbucket[0], value); 25273c7a4f2SDebasis Das break; 25396a1be4fSAniruddha Paul default: 25496a1be4fSAniruddha Paul break; 25596a1be4fSAniruddha Paul } 25696a1be4fSAniruddha Paul 25796a1be4fSAniruddha Paul if (idx == CDP_HIST_BUCKET_MAX) 25896a1be4fSAniruddha Paul return; 25996a1be4fSAniruddha Paul 26096a1be4fSAniruddha Paul hist_bucket->freq[idx]++; 26196a1be4fSAniruddha Paul } 26296a1be4fSAniruddha Paul 26396a1be4fSAniruddha Paul void dp_hist_update_stats(struct cdp_hist_stats *hist_stats, int value) 26496a1be4fSAniruddha Paul { 26596a1be4fSAniruddha Paul if (qdf_unlikely(!hist_stats)) 26696a1be4fSAniruddha Paul return; 26796a1be4fSAniruddha Paul 26896a1be4fSAniruddha Paul /* 26996a1be4fSAniruddha Paul * Fill the histogram buckets according to the delay 27096a1be4fSAniruddha Paul */ 27196a1be4fSAniruddha Paul dp_hist_fill_buckets(&hist_stats->hist, value); 27296a1be4fSAniruddha Paul 27396a1be4fSAniruddha Paul /* 27496a1be4fSAniruddha Paul * Compute the min, max and average. Average computed is weighted 27596a1be4fSAniruddha Paul * average 27696a1be4fSAniruddha Paul */ 27796a1be4fSAniruddha Paul if (value < hist_stats->min) 27896a1be4fSAniruddha Paul hist_stats->min = value; 27996a1be4fSAniruddha Paul 28096a1be4fSAniruddha Paul if (value > hist_stats->max) 28196a1be4fSAniruddha Paul hist_stats->max = value; 28296a1be4fSAniruddha Paul 28396a1be4fSAniruddha Paul if (qdf_unlikely(!hist_stats->avg)) 28496a1be4fSAniruddha Paul hist_stats->avg = value; 28596a1be4fSAniruddha Paul else 286e7615d09SDebasis Das hist_stats->avg = (hist_stats->avg + value) / 2; 28796a1be4fSAniruddha Paul } 28896a1be4fSAniruddha Paul 2899088f48eSAniruddha Paul void dp_copy_hist_stats(struct cdp_hist_stats *src_hist_stats, 2909088f48eSAniruddha Paul struct cdp_hist_stats *dst_hist_stats) 2919088f48eSAniruddha Paul { 2929088f48eSAniruddha Paul uint8_t index; 2939088f48eSAniruddha Paul 2949088f48eSAniruddha Paul for (index = 0; index < CDP_HIST_BUCKET_MAX; index++) 2959088f48eSAniruddha Paul dst_hist_stats->hist.freq[index] = 2969088f48eSAniruddha Paul src_hist_stats->hist.freq[index]; 2979088f48eSAniruddha Paul dst_hist_stats->min = src_hist_stats->min; 2989088f48eSAniruddha Paul dst_hist_stats->max = src_hist_stats->max; 2999088f48eSAniruddha Paul dst_hist_stats->avg = src_hist_stats->avg; 3009088f48eSAniruddha Paul } 3019088f48eSAniruddha Paul 3029088f48eSAniruddha Paul void dp_accumulate_hist_stats(struct cdp_hist_stats *src_hist_stats, 3039088f48eSAniruddha Paul struct cdp_hist_stats *dst_hist_stats) 3049088f48eSAniruddha Paul { 305e7615d09SDebasis Das uint8_t index, hist_stats_valid = 0; 3069088f48eSAniruddha Paul 307e7615d09SDebasis Das for (index = 0; index < CDP_HIST_BUCKET_MAX; index++) { 3089088f48eSAniruddha Paul dst_hist_stats->hist.freq[index] += 3099088f48eSAniruddha Paul src_hist_stats->hist.freq[index]; 310e7615d09SDebasis Das if (src_hist_stats->hist.freq[index]) 311e7615d09SDebasis Das hist_stats_valid = 1; 312e7615d09SDebasis Das } 313e7615d09SDebasis Das /* 314e7615d09SDebasis Das * If at least one hist-bucket has non-zero count, 315e7615d09SDebasis Das * proceed with the detailed calculation. 316e7615d09SDebasis Das */ 317e7615d09SDebasis Das if (hist_stats_valid) { 318e7615d09SDebasis Das dst_hist_stats->min = QDF_MIN(src_hist_stats->min, 319e7615d09SDebasis Das dst_hist_stats->min); 320e7615d09SDebasis Das dst_hist_stats->max = QDF_MAX(src_hist_stats->max, 321e7615d09SDebasis Das dst_hist_stats->max); 322e7615d09SDebasis Das dst_hist_stats->avg = (src_hist_stats->avg + 323e7615d09SDebasis Das dst_hist_stats->avg) >> 1; 324e7615d09SDebasis Das } 3259088f48eSAniruddha Paul } 3269088f48eSAniruddha Paul 32796a1be4fSAniruddha Paul void dp_hist_init(struct cdp_hist_stats *hist_stats, 32896a1be4fSAniruddha Paul enum cdp_hist_types hist_type) 32996a1be4fSAniruddha Paul { 33096a1be4fSAniruddha Paul qdf_mem_zero(hist_stats, sizeof(*hist_stats)); 3314bdcc0d4SDebasis Das hist_stats->min = INT_MAX; 33296a1be4fSAniruddha Paul hist_stats->hist.hist_type = hist_type; 33396a1be4fSAniruddha Paul } 334