An open API service indexing awesome lists of open source software.

https://github.com/amirreza81/software-engineering-lab-exp5


https://github.com/amirreza81/software-engineering-lab-exp5

Last synced: 5 months ago
JSON representation

Awesome Lists containing this project

README

          

# آزمایش پنجم - Profiling

## بخش اول - پروفایلینگ JavaCup
در ابتدا کد JavaCup را با استفاده از YourKit ران کرده و Profiling را انجام می دهیم. ابتدا مشاهده می شود که برنامه تا آخر اجرا نشده است و ارور OutOfMemory داده است:

![photo_2025-05-12_11-59-58](https://github.com/user-attachments/assets/8a59ad6c-3e8c-4756-a4bf-f68e521bb513)

سپس آنالیز را با استفاده از YourKit انجام می دهیم. با توجه به داده های گزارش شده می توان فهمید که تابع temp بیشترین میزان مصرف را دارد و باعث ارور دادن برنامه می شود:

![photo_2025-05-12_12-00-49](https://github.com/user-attachments/assets/0bbf2ba1-5a46-45af-8e27-b5d54ba0ef40)

![photo_2025-05-12_12-01-05](https://github.com/user-attachments/assets/88ca3069-673a-41c5-9573-97677f83f091)

![photo_2025-05-12_12-01-12](https://github.com/user-attachments/assets/b09f9362-aebc-4c47-a6eb-9f9a1b51f37f)

![photo_2025-05-12_12-01-16](https://github.com/user-attachments/assets/215c723d-63af-49fd-835d-96a4055dec08)

در این تابع، یک ArrayList به نام a ایجاد می‌شود که در هر بار اجرای حلقه‌های تو در تو، برای هر ترکیب از i و j یک مقدار جدید به آن افزوده می‌شود. این فرآیند باعث ایجاد تعداد زیادی شیء و افزایش غیرضروری در مصرف حافظه و زمان پردازش می‌گردد. زیرا ArrayList به صورت پویا عمل می‌کند و با هر بار افزودن عنصر جدید، ممکن است نیاز به تخصیص حافظه‌ی تازه‌ای داشته باشد. زمانی که تعداد تکرارها زیاد باشد، این تخصیص‌های مکرر حافظه و گسترش پیاپی ظرفیت لیست، منجر به مصرف زیاد منابع و کاهش کارایی کلی برنامه می‌شود. بنابراین با این متد پیش رفتن باعث پر شدن حافظه و ارور OutOfMemory می شود:

![Screenshot 2025-05-12 121847](https://github.com/user-attachments/assets/374bbe60-e6e6-44b1-b005-6fc61d1e623e)

برای بهینه‌سازی مصرف منابع، به جای استفاده از ArrayList که به‌صورت پویا حافظه را مدیریت می‌کند، می‌توان از یک آرایه‌ی دوبعدی با اندازه‌ی مشخص استفاده کرد. این روش باعث می‌شود حافظه از ابتدا به‌طور کامل تخصیص داده شود و نیازی به افزایش تدریجی ظرفیت یا جابجایی داده‌ها در حافظه نباشد. در نسخه بهینه‌شده، یک آرایه‌ی دوبعدی از نوع int با ابعاد ۲۰۰۰۰ در ۱۰۰۰۰ تعریف شده است، که هر مقدار مستقیماً در مکان مناسب خود در آرایه قرار می‌گیرد. با این کار، مدیریت حافظه ساده‌تر و کارآمدتر می‌شود و از سربار ناشی از ساختارهای داینامیک جلوگیری خواهد شد:

![photo_2025-05-12_12-01-20](https://github.com/user-attachments/assets/8e1d2484-91fd-4e38-899c-a061a3e8185e)

حال دوباره عمل Profiling را انجام می دهیم. در ابتدا مشاهده می شود که برنامه تا انتها اجرا شده است:

![photo_2025-05-12_12-01-23](https://github.com/user-attachments/assets/e2ff4a61-8464-4feb-9f47-9478f83478bb)

همچنین با استفاده از YourKit می توان مشاهده کرد مقدار استفاده از منابع نیز بسیار کاهش یافته است:

![photo_2025-05-12_12-01-26](https://github.com/user-attachments/assets/a7c9efde-fa29-4232-adfa-ec95659715e5)

![photo_2025-05-12_12-01-30](https://github.com/user-attachments/assets/98903a19-f2b0-4057-a436-e9328735d8b8)

![photo_2025-05-12_12-01-33](https://github.com/user-attachments/assets/9200250f-02b6-474a-be81-fa31e909c134)

---

## بخش دوم

در این بخش کدی را پیاده‌سازی کرده‌ایم که لیستی از یک میلیون عدد تولید می‌کند و بررسی می‌کند که آیا عدد تکراری وجود دارد یا نه.

#### چرا این نسخه ناکارآمد است؟

در کد زیر، از ArrayList برای بررسی تکراری بودن استفاده شده:

```java
List seen = new ArrayList<>();
for (Integer num : list) {
if (seen.contains(num)) {
return true;
}
seen.add(num);
}
```

- متد `contains()` در ArrayList زمان اجرای O(n) دارد.
- این حلقه برای هر عدد اجرا می‌شود، بنابراین کل الگوریتم دارای پیچیدگی O(n^2) است.
- در لیست‌های بزرگ بسیار کند و پرمصرف است.

حال به بررسی Profiling بر روی آن می‌پردازیم. در ابتدا مشاهده می‌کنیم کد به دلیل هزینه محاسباتی بالا خروجی‌ای تولید نمی‌کند .

![image1](pics/1.png)

سپس به سراغ yourkit رفته و دقیقا نتایج مورد انتظار را مشاهده می‌نماییم:

![image2](pics/2.png)
![image3](pics/3.png)
![image4](pics/4.png)
![image5](pics/5.png)
![image6](pics/6.png)

### بهبود الگوریتم
برای بهبود این کد می‌توان از مکانیزم hashing استفاده کرد تا پیچیدگی زمانی کد کاهش پیدا کند. در واقع ما اعداد را به ترتیب به یک hashset اضافه می‌کنیم و قبل از اضافه کردن هر عضو،
چک می‌کنیم که آیا در hashset ما وجود دارد یا خیر.
در واقع بررسی موجود بودن یک عضو در hashset،
دارای پیچیدگی O(1)
است، پس یعنی به طور کلی پیچیدگی کد ما O(n)
خواهد که به مراتب نسبت به حالت اول بهینه تر است.
در ادامه کد مربوط به قسمت hash را می‌بینید.
```java
Set seen = new HashSet<>();
for (Integer num : list) {
if (!seen.add(num)) {
return true;
}
}
```
همچنین با استفاده از yourkit کدمان را بررسی می‌کنیم
و مشاهده می‌کنیم که بهبود مورد انتظار حاصل شده است.

![image5](pics/10.jpg)

![image2](pics/7.jpg)
![image3](pics/8.jpg)
![image4](pics/9.jpg)

---

### تقسیم کار
در این آزمایش تلاش شد تا تسک‌ها به طور یکسان بین اعضای تیم پخش شود.
بخش اول که بررسی Profiling بر پروژه داده شده و اصلاح آ« بود را یک نفر انجام داد. بخش دوم و الگوریتم با زمان اجرای بد و نهایی کردن گزارش کل پروژه را یک فرد و اصلاح کد جدید را یک شخص دیگر انجام داد. همچنین هر شخص گرازش مربوط به بخش خود را نیز تکمیل نمود.

[لینک کانبان‌برد](https://github.com/users/Amirreza81/projects/3)

---

### اعضای تیم
- امیررضا آذری - 99101087
- رضا حیدری - 400109616
- امید دلیران - 400104931