Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

322 lines
11KB

  1. #!/usr/bin/env python3
  2. import math
  3. import multiprocessing
  4. import os
  5. from argparse import ArgumentParser
  6. import matplotlib
  7. import numpy as np
  8. import pandas as pd
  9. import matplotlib.pyplot as plt
  10. # Using seaborn's style
  11. # plt.style.use('seaborn')
  12. tex_fonts = {
  13. "pgf.texsystem": "lualatex",
  14. # "legend.fontsize": "x-large",
  15. # "figure.figsize": (15, 5),
  16. "axes.labelsize": 15, # "small",
  17. # "axes.titlesize": "x-large",
  18. "xtick.labelsize": 15, # "small",
  19. "ytick.labelsize": 15, # "small",
  20. "legend.fontsize": 15,
  21. "axes.formatter.use_mathtext": True,
  22. "mathtext.fontset": "dejavusans",
  23. }
  24. # plt.rcParams.update(tex_fonts)
  25. def convert_cellid(value):
  26. if isinstance(value, str):
  27. try:
  28. r = int(value.split(" ")[-1].replace("(", "").replace(")", ""))
  29. return r
  30. except Exception as e:
  31. return -1
  32. else:
  33. return int(-1)
  34. if __name__ == "__main__":
  35. parser = ArgumentParser()
  36. parser.add_argument("-s", "--serial_file", required=True, help="Serial csv file.")
  37. parser.add_argument(
  38. "-p", "--pcap_csv_folder", required=True, help="PCAP csv folder."
  39. )
  40. parser.add_argument("--save", required=True, help="Location to save pdf file.")
  41. parser.add_argument(
  42. "-i",
  43. "--interval",
  44. default=10,
  45. type=int,
  46. help="Time interval for rolling window.",
  47. )
  48. args = parser.parse_args()
  49. pcap_csv_list = list()
  50. for filename in os.listdir(args.pcap_csv_folder):
  51. if filename.endswith(".csv") and "tcp" in filename:
  52. pcap_csv_list.append(filename)
  53. counter = 1
  54. if len(pcap_csv_list) == 0:
  55. print("No CSV files found.")
  56. pcap_csv_list.sort(key=lambda x: int(x.split("_")[-1].replace(".csv", "")))
  57. for csv in pcap_csv_list:
  58. print(
  59. "\rProcessing {} out of {} CSVs.\t({}%)\t".format(
  60. counter, len(pcap_csv_list), math.floor(counter / len(pcap_csv_list))
  61. )
  62. )
  63. # try:
  64. transmission_df = pd.read_csv(
  65. "{}{}".format(args.pcap_csv_folder, csv),
  66. dtype=dict(is_retranmission=bool, is_dup_ack=bool),
  67. )
  68. transmission_df["datetime"] = pd.to_datetime(
  69. transmission_df["datetime"]
  70. ) - pd.Timedelta(hours=1)
  71. transmission_df = transmission_df.set_index("datetime")
  72. transmission_df.index = pd.to_datetime(transmission_df.index)
  73. transmission_df = transmission_df.sort_index()
  74. # srtt to [s]
  75. transmission_df["srtt"] = transmission_df["srtt"].apply(lambda x: x / 10**6)
  76. # key for columns and level for index
  77. transmission_df["goodput"] = (
  78. transmission_df["payload_size"]
  79. .groupby(pd.Grouper(level="datetime", freq="{}s".format(args.interval)))
  80. .transform("sum")
  81. )
  82. transmission_df["goodput"] = transmission_df["goodput"].apply(
  83. lambda x: ((x * 8) / args.interval) / 10**6
  84. )
  85. transmission_df["goodput_rolling"] = (
  86. transmission_df["payload_size"].rolling("{}s".format(args.interval)).sum()
  87. )
  88. transmission_df["goodput_rolling"] = transmission_df["goodput_rolling"].apply(
  89. lambda x: ((x * 8) / args.interval) / 10**6
  90. )
  91. # set meta values and remove all not needed columns
  92. cc_algo = transmission_df["congestion_control"].iloc[0]
  93. cc_algo = cc_algo.upper()
  94. transmission_direction = transmission_df["direction"].iloc[0]
  95. # transmission_df = transmission_df.filter(["goodput", "datetime", "ack_rtt", "goodput_rolling", "snd_cwnd"])
  96. # read serial csv
  97. serial_df = pd.read_csv(
  98. args.serial_file, converters={"Cell_ID": convert_cellid}
  99. )
  100. serial_df["datetime"] = pd.to_datetime(serial_df["datetime"]) - pd.Timedelta(
  101. hours=1
  102. )
  103. serial_df = serial_df.set_index("datetime")
  104. serial_df.index = pd.to_datetime(serial_df.index)
  105. serial_df.sort_index()
  106. # print(serial_df["Cell_ID"])
  107. # serial_df["Cell_ID"] = serial_df["Cell_ID"].apply(
  108. # lambda x: int(x.split(" ")[-1].replace("(", "").replace(")", "")))
  109. transmission_df = pd.merge_asof(
  110. transmission_df,
  111. serial_df,
  112. tolerance=pd.Timedelta("1s"),
  113. right_index=True,
  114. left_index=True,
  115. )
  116. transmission_df.index = transmission_df["arrival_time"]
  117. # replace 0 in RSRQ with Nan
  118. transmission_df["NR5G_RSRQ_(dB)"] = transmission_df["NR5G_RSRQ_(dB)"].replace(
  119. 0, np.NaN
  120. )
  121. transmission_df["RSRQ_(dB)"] = transmission_df["RSRQ_(dB)"].replace(0, np.NaN)
  122. # filter active state
  123. for i in range(1, 5):
  124. transmission_df["LTE_SCC{}_effective_bw".format(i)] = transmission_df[
  125. "LTE_SCC{}_bw".format(i)
  126. ]
  127. mask = transmission_df["LTE_SCC{}_state".format(i)].isin(["ACTIVE"])
  128. transmission_df["LTE_SCC{}_effective_bw".format(i)] = transmission_df[
  129. "LTE_SCC{}_effective_bw".format(i)
  130. ].where(mask, other=0)
  131. # filter if sc is usesd for uplink
  132. for i in range(1, 5):
  133. mask = transmission_df["LTE_SCC{}_UL_Configured".format(i)].isin([False])
  134. transmission_df["LTE_SCC{}_effective_bw".format(i)] = transmission_df[
  135. "LTE_SCC{}_effective_bw".format(i)
  136. ].where(mask, other=0)
  137. # sum all effective bandwidth for 5G and 4G
  138. transmission_df["SCC1_NR5G_effective_bw"] = transmission_df[
  139. "SCC1_NR5G_bw"
  140. ].fillna(0)
  141. transmission_df["effective_bw_sum"] = (
  142. transmission_df["SCC1_NR5G_effective_bw"]
  143. + transmission_df["LTE_SCC1_effective_bw"]
  144. + transmission_df["LTE_SCC2_effective_bw"]
  145. + transmission_df["LTE_SCC3_effective_bw"]
  146. + transmission_df["LTE_SCC4_effective_bw"]
  147. + transmission_df["LTE_bw"]
  148. )
  149. transmission_df["lte_effective_bw_sum"] = (
  150. transmission_df["LTE_SCC1_effective_bw"]
  151. + transmission_df["LTE_SCC2_effective_bw"]
  152. + transmission_df["LTE_SCC3_effective_bw"]
  153. + transmission_df["LTE_SCC4_effective_bw"]
  154. + transmission_df["LTE_bw"])
  155. transmission_df["nr_effective_bw_sum"] = transmission_df["SCC1_NR5G_effective_bw"]
  156. # transmission timeline
  157. scaley = 1.5
  158. scalex = 1.0
  159. plt.title("{} with {}".format(transmission_direction, cc_algo))
  160. fig, ax = plt.subplots(2, 1, figsize=[6.4 * scaley, 4.8 * scalex])
  161. fig.subplots_adjust(right=0.75)
  162. fig.suptitle("{} with {}".format(transmission_direction, cc_algo))
  163. ax0 = ax[0]
  164. ax1 = ax0.twinx()
  165. ax2 = ax0.twinx()
  166. # ax2.spines.right.set_position(("axes", 1.22))
  167. ax00 = ax[1]
  168. ax01 = ax00.twinx()
  169. ax02 = ax00.twinx()
  170. # Plot vertical lines
  171. first = True
  172. lte_handovers = transmission_df["Cell_ID"].dropna().diff()
  173. for index, value in lte_handovers.items():
  174. if value > 0:
  175. if first:
  176. ax00.axvline(
  177. index, ymin=0, ymax=1, color="skyblue", label="4G Handover"
  178. )
  179. first = False
  180. else:
  181. ax00.axvline(index, ymin=0, ymax=1, color="skyblue")
  182. first = True
  183. nr_handovers = (
  184. transmission_df["NR5G_Cell_ID"].replace(0, np.NaN).dropna().diff()
  185. )
  186. for index, value in nr_handovers.items():
  187. if value > 0:
  188. if first:
  189. ax00.axvline(
  190. index, ymin=0, ymax=1, color="greenyellow", label="5G Handover"
  191. )
  192. first = False
  193. else:
  194. ax00.axvline(index, ymin=0, ymax=1, color="greenyellow")
  195. ax0.plot(
  196. transmission_df["snd_cwnd"].dropna(),
  197. color="lime",
  198. linestyle="dashed",
  199. label="cwnd",
  200. )
  201. ax1.plot(
  202. transmission_df["srtt"].dropna(),
  203. color="red",
  204. linestyle="dashdot",
  205. label="sRTT",
  206. )
  207. ax2.plot(
  208. transmission_df["goodput_rolling"],
  209. color="blue",
  210. linestyle="solid",
  211. label="goodput",
  212. )
  213. # ax2.plot(transmission_df["goodput"], color="blue", linestyle="solid", label="goodput")
  214. ax01.plot(
  215. transmission_df["effective_bw_sum"].dropna(),
  216. color="peru",
  217. linestyle="solid",
  218. label="bandwidth",
  219. )
  220. ax01.plot(
  221. transmission_df["lte_effective_bw_sum"].dropna(),
  222. color="lightsteelblue",
  223. linestyle="solid",
  224. label="4G bandwidth",
  225. alpha=0.5,
  226. )
  227. ax01.plot(
  228. transmission_df["nr_effective_bw_sum"].dropna(),
  229. color="cornflowerblue",
  230. linestyle="solid",
  231. label="5G bandwidth",
  232. alpha=0.5,
  233. )
  234. # ax01.stackplot(transmission_df["arrival_time"].to_list(),
  235. # [transmission_df["lte_bw_sum"].to_list(), transmission_df["nr_bw_sum"].to_list()],
  236. # colors=["lightsteelblue", "cornflowerblue"],
  237. # labels=["4G bandwidth", "5G bandwidth"]
  238. # )
  239. ax02.plot(
  240. transmission_df["RSRQ_(dB)"].dropna(),
  241. color="purple",
  242. linestyle="dotted",
  243. label="LTE RSRQ",
  244. )
  245. ax00.plot(
  246. transmission_df["NR5G_RSRQ_(dB)"].dropna(),
  247. color="magenta",
  248. linestyle="dotted",
  249. label="NR RSRQ",
  250. )
  251. ax2.spines.right.set_position(("axes", 1.1))
  252. ax02.spines.right.set_position(("axes", 1.1))
  253. ax0.set_ylim(0, 5000)
  254. ax1.set_ylim(0, 0.3)
  255. ax2.set_ylim(0, 500)
  256. ax00.set_ylim(-25, 0)
  257. ax01.set_ylim(0, 250)
  258. # second dB axis
  259. ax02.set_ylim(-25, 0)
  260. ax02.set_axis_off()
  261. ax00.set_xlabel("arrival time [s]")
  262. ax2.set_ylabel("Goodput [mbps]")
  263. ax00.set_ylabel("LTE/NR RSRQ [dB]")
  264. # ax02.set_ylabel("LTE RSRQ [dB]")
  265. ax1.set_ylabel("sRTT [s]")
  266. ax0.set_ylabel("cwnd")
  267. ax01.set_ylabel("Bandwidth [MHz]")
  268. fig.legend(loc="lower right")
  269. plt.savefig("{}{}_plot.pdf".format(args.save, csv.replace(".csv", "")))
  270. # except Exception as e:
  271. # print("Error processing file: {}".format(csv))
  272. # print(str(e))
  273. counter += 1
  274. plt.close(fig)
  275. plt.clf()