Skip to content

Commit 1983898

Browse files
committed
ft-analyzer read only required csv columns and add garbage collection calls
1 parent f7bbd80 commit 1983898

2 files changed

Lines changed: 94 additions & 53 deletions

File tree

tools/ft-analyzer/ftanalyzer/events/events.py

Lines changed: 81 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,16 @@
88
from typing import Iterator
99
import numpy as np
1010
import pandas as pd
11+
import gc
1112

1213
CSV_COLUMN_TYPES = {
1314
"START_TIME": np.uint64,
1415
"END_TIME": np.uint64,
15-
"PROTOCOL": np.uint8,
16-
"SRC_IP": str,
17-
"DST_IP": str,
18-
"SRC_PORT": np.uint16,
19-
"DST_PORT": np.uint16,
16+
# "PROTOCOL": np.uint8,
17+
# "SRC_IP": str,
18+
# "DST_IP": str,
19+
# "SRC_PORT": np.uint16,
20+
# "DST_PORT": np.uint16,
2021
"PACKETS": np.uint64,
2122
"BYTES": np.uint64,
2223
"EXPORT_TIME": np.uint64,
@@ -34,44 +35,44 @@
3435

3536
STATS_CSV_COLUMN_TYPES = {
3637
"Time": np.uint64,
37-
"UID": np.uint64,
38-
"PID": np.uint64,
39-
"percent_usr": np.float64,
40-
"percent_system": np.float64,
41-
"percent_guest": np.float64,
42-
"percent_wait": np.float64,
38+
# "UID": np.uint64,
39+
# "PID": np.uint64,
40+
# "percent_usr": np.float64,
41+
# "percent_system": np.float64,
42+
# "percent_guest": np.float64,
43+
# "percent_wait": np.float64,
4344
"percent_CPU": np.float64,
44-
"CPU": np.uint64,
45-
"minflt/s": np.float64,
46-
"majflt/s": np.float64,
47-
"VSZ": np.uint64,
48-
"RSS": np.uint64,
45+
# "CPU": np.uint64,
46+
# "minflt/s": np.float64,
47+
# "majflt/s": np.float64,
48+
# "VSZ": np.uint64,
49+
# "RSS": np.uint64,
4950
"percent_MEM": np.float64,
50-
"StkSize": np.uint64,
51-
"StkRef": np.uint64,
52-
"threads": np.uint64,
53-
"fd-nr": np.uint64,
54-
"Command": str,
51+
# "StkSize": np.uint64,
52+
# "StkRef": np.uint64,
53+
# "threads": np.uint64,
54+
# "fd-nr": np.uint64,
55+
# "Command": str,
5556
}
5657

5758
SUM_PIDSTAT_COLS = [
58-
"percent_usr",
59-
"percent_system",
60-
"percent_guest",
61-
"percent_wait",
59+
# "percent_usr",
60+
# "percent_system",
61+
# "percent_guest",
62+
# "percent_wait",
6263
"percent_CPU",
63-
"minflt/s",
64-
"majflt/s",
65-
"fd-nr",
64+
# "minflt/s",
65+
# "majflt/s",
66+
# "fd-nr",
6667
]
6768
TAKE_PIDSTAT_COLS = [
68-
"RSS",
69-
"VSZ",
69+
# "RSS",
70+
# "VSZ",
7071
"percent_MEM",
71-
"threads",
72-
"UID",
73-
"Command",
74-
"CPU",
72+
# "threads",
73+
# "UID",
74+
# "Command",
75+
# "CPU",
7576
"Time",
7677
]
7778

@@ -166,7 +167,7 @@ def __init__(self, row):
166167

167168

168169
def create_event_queue(
169-
flows_csv_path: os.PathLike, hosts_stats_file: os.PathLike, out_dir: str = None
170+
flows_path: os.PathLike, hosts_stats_file: os.PathLike, out_dir: str = None
170171
) -> Iterator[Event]:
171172
if not out_dir:
172173
out_dir = tempfile.mkdtemp(prefix="flows_split_")
@@ -184,15 +185,19 @@ def create_event_queue(
184185
sorted_by_export_path = os.path.join(out_dir, "flows_sorted_by_export.csv")
185186

186187
# Load and split
187-
df = pd.read_csv(flows_csv_path, dtype=CSV_COLUMN_TYPES)
188-
df.fillna(0)
188+
df = pd.read_csv(
189+
flows_path,
190+
dtype=CSV_COLUMN_TYPES,
191+
usecols=CSV_COLUMN_TYPES.keys(),
192+
engine="pyarrow",
193+
)
189194

190195
# Filer host stats file by time
191196
start = math.floor(df["START_TIME"].min() / 1000)
192197
end = math.ceil(df["END_TIME"].max() / 1000)
193198

194199
stats_df: pd.DataFrame = pd.read_csv(
195-
hosts_stats_file, sep=";", dtype=STATS_CSV_COLUMN_TYPES
200+
hosts_stats_file, sep=";", dtype=STATS_CSV_COLUMN_TYPES, engine="pyarrow"
196201
)
197202
stats_df = stats_df[(stats_df["Time"] >= start) & (stats_df["Time"] <= end)]
198203

@@ -216,15 +221,6 @@ def create_event_queue(
216221
.to_csv(one_packet_path, index=False)
217222
)
218223

219-
# Multi-packet flows
220-
multi_df = (
221-
df[df["PACKETS"] > 1]
222-
.groupby(["START_TIME", "END_TIME"], as_index=False)
223-
.agg(**agg_dict)
224-
)
225-
multi_df.sort_values("START_TIME").to_csv(sorted_by_start_path, index=False)
226-
multi_df.sort_values("END_TIME").to_csv(sorted_by_end_path, index=False)
227-
228224
# Export Events
229225
if "EXPORT_TIME" in df.columns:
230226
df.groupby(["EXPORT_TIME", "SEQ_NUMBER"], as_index=False).agg(
@@ -235,6 +231,20 @@ def create_event_queue(
235231
with open(sorted_by_export_path, "w+") as f:
236232
f.write("EXPORT_TIME,SEQ_NUMBER,FLOWS,MSG_LENGTH")
237233

234+
# Multi-packet flows
235+
multi_df = (
236+
df[df["PACKETS"] > 1]
237+
.groupby(["START_TIME", "END_TIME"], as_index=False)
238+
.agg(**agg_dict)
239+
)
240+
del df
241+
gc.collect()
242+
multi_df.sort_values("START_TIME").to_csv(sorted_by_start_path, index=False)
243+
gc.collect()
244+
multi_df.sort_values("END_TIME").to_csv(sorted_by_end_path, index=False)
245+
del multi_df
246+
gc.collect()
247+
238248
return heapq.merge(
239249
read_one_packet_events(one_packet_path),
240250
read_start_events(sorted_by_start_path),
@@ -254,6 +264,7 @@ def read_export_events(path: os.PathLike):
254264
"FLOWS": np.uint64,
255265
"MSG_LENGTH": np.uint64,
256266
},
267+
usecols=["EXPORT_TIME", "SEQ_NUMBER", "FLOWS", "MSG_LENGTH"],
257268
chunksize=100_000,
258269
):
259270
for row in chunk.itertuples(index=False):
@@ -266,7 +277,11 @@ def read_export_events(path: os.PathLike):
266277

267278
def read_host_stats_events(path: os.PathLike):
268279
for chunk in pd.read_csv(
269-
path, chunksize=100_000, sep=";", dtype=STATS_CSV_COLUMN_TYPES
280+
path,
281+
chunksize=100_000,
282+
sep=";",
283+
dtype=STATS_CSV_COLUMN_TYPES,
284+
usecols=STATS_CSV_COLUMN_TYPES.keys(),
270285
):
271286
for row in chunk.itertuples(index=False):
272287
yield HostStatsEvent(row)
@@ -276,7 +291,12 @@ def read_one_packet_events(path: str) -> Iterator[OnePacketFlow]:
276291
CSV_AGGREGATE_TYPES_NO_END = {
277292
k: v for k, v in CSV_AGGREGATE_TYPES.items() if k != "END_TIME"
278293
}
279-
for chunk in pd.read_csv(path, dtype=CSV_AGGREGATE_TYPES_NO_END, chunksize=100_000):
294+
for chunk in pd.read_csv(
295+
path,
296+
dtype=CSV_AGGREGATE_TYPES_NO_END,
297+
chunksize=100_000,
298+
usecols=CSV_AGGREGATE_TYPES_NO_END.keys(),
299+
):
280300
for row in chunk.itertuples(index=False):
281301
yield OnePacketFlow(
282302
bytes=np.uint64(row.BYTES),
@@ -287,7 +307,12 @@ def read_one_packet_events(path: str) -> Iterator[OnePacketFlow]:
287307

288308

289309
def read_start_events(path: str) -> Iterator[FlowStartEvent]:
290-
for chunk in pd.read_csv(path, dtype=CSV_AGGREGATE_TYPES, chunksize=100_000):
310+
for chunk in pd.read_csv(
311+
path,
312+
dtype=CSV_AGGREGATE_TYPES,
313+
chunksize=100_000,
314+
usecols=CSV_AGGREGATE_TYPES.keys(),
315+
):
291316
durations = (chunk.END_TIME - chunk.START_TIME + 1) / 1_000
292317
data_rates = (chunk.BYTES * 8) / durations
293318
packet_rates = chunk.PACKETS / durations
@@ -305,7 +330,12 @@ def read_start_events(path: str) -> Iterator[FlowStartEvent]:
305330

306331

307332
def read_end_events(path: str) -> Iterator[FlowEndEvent]:
308-
for chunk in pd.read_csv(path, dtype=CSV_AGGREGATE_TYPES, chunksize=100_000):
333+
for chunk in pd.read_csv(
334+
path,
335+
dtype=CSV_AGGREGATE_TYPES,
336+
chunksize=100_000,
337+
usecols=CSV_AGGREGATE_TYPES.keys(),
338+
):
309339
durations = (chunk.END_TIME - chunk.START_TIME + 1) / 1_000
310340
data_rates = (chunk.BYTES * 8) / durations
311341
packet_rates = chunk.PACKETS / durations

tools/ft-analyzer/ftanalyzer/models/statistical_model.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import atexit
1010
from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
11+
import gc
1112
import ipaddress
1213
import logging
1314
import operator
@@ -169,6 +170,7 @@ def __init__(
169170
try:
170171
logging.getLogger().debug("reading file with flows=%s", flows)
171172
# ports could be empty in flows with protocol like ICMP
173+
self._flows_path = flows
172174
flows = pd.read_csv(flows, engine="pyarrow", dtype=self.CSV_COLUMN_TYPES)
173175
flows["SRC_PORT"] = flows["SRC_PORT"].fillna(0)
174176
flows["DST_PORT"] = flows["DST_PORT"].fillna(0)
@@ -179,6 +181,7 @@ def __init__(
179181
self._ref = pd.read_csv(
180182
reference, engine="pyarrow", dtype=self.CSV_COLUMN_TYPES
181183
)
184+
self._ref_path = reference
182185
else:
183186
self._ref = reference
184187
except Exception as err:
@@ -205,15 +208,23 @@ def __init__(
205208
self._merge_flows(biflows_ts_correction)
206209

207210
# write dataframes back to file and read later when needed
208-
self._flows_path = tempfile.NamedTemporaryFile(delete=False, suffix=".csv").name
211+
if not (hasattr(self, "_flows_path") and self._flows_path):
212+
self._flows_path = tempfile.NamedTemporaryFile(
213+
delete=False, suffix=".csv"
214+
).name
209215
self._flows.to_csv(self._flows_path, index=False)
210216
del self._flows
217+
gc.collect()
211218

212219
_TEMP_FILES.append(self._flows_path)
213220

214-
self._ref_path = tempfile.NamedTemporaryFile(delete=False, suffix=".csv").name
221+
if not (hasattr(self, "_ref_path") and self._ref_path):
222+
self._ref_path = tempfile.NamedTemporaryFile(
223+
delete=False, suffix=".csv"
224+
).name
215225
self._ref.to_csv(self._ref_path, index=False)
216226
del self._ref
227+
gc.collect()
217228

218229
_TEMP_FILES.append(self._ref_path)
219230

0 commit comments

Comments
 (0)