Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

344 rindas
12KB

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