diff --git a/.github/workflows/update-download-stats.yml b/.github/workflows/update-download-stats.yml
new file mode 100644
index 0000000..5e6cfa6
--- /dev/null
+++ b/.github/workflows/update-download-stats.yml
@@ -0,0 +1,39 @@
+name: Update Download Statistics
+
+on:
+ schedule:
+ # Run daily at 00:00 UTC
+ - cron: "0 0 * * *"
+ workflow_dispatch:
+
+jobs:
+ update-stats:
+ name: Update download statistics and graph
+ runs-on: ubuntu-latest
+ permissions:
+ contents: write
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ - name: Set up Python
+ uses: actions/setup-python@v5
+
+ - name: Install dependencies
+ run: |
+ pip install requests matplotlib
+
+ - name: Update download statistics
+ run: |
+ python update_download_stats.py
+
+ - name: Commit and push changes
+ run: |
+ git config --global user.name "github-actions[bot]"
+ git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
+ git add docs/data/download_history.json docs/data/download_graph.png
+ git diff --staged --quiet || git commit -m "chore: update download statistics
+
+ Update download statistics and graph for $(date -u +%Y-%m-%d)"
+ git push
diff --git a/README.md b/README.md
index fa865e1..d1ff186 100644
--- a/README.md
+++ b/README.md
@@ -136,6 +136,34 @@ If you use this repository in your research and find it helpful, please cite the
}
```
+## Star History and Download Statistics
+
+
+
## Original Repository
[repo](https://github.com/Dao-AILab/flash-attention)
+
+```bibtex
+@inproceedings{dao2022flashattention,
+ title={Flash{A}ttention: Fast and Memory-Efficient Exact Attention with {IO}-Awareness},
+ author={Dao, Tri and Fu, Daniel Y. and Ermon, Stefano and Rudra, Atri and R{\'e}, Christopher},
+ booktitle={Advances in Neural Information Processing Systems (NeurIPS)},
+ year={2022}
+}
+@inproceedings{dao2023flashattention2,
+ title={Flash{A}ttention-2: Faster Attention with Better Parallelism and Work Partitioning},
+ author={Dao, Tri},
+ booktitle={International Conference on Learning Representations (ICLR)},
+ year={2024}
+}
+```
diff --git a/docs/data/download_graph.png b/docs/data/download_graph.png
new file mode 100644
index 0000000..c6dc3ef
Binary files /dev/null and b/docs/data/download_graph.png differ
diff --git a/docs/data/download_history.json b/docs/data/download_history.json
new file mode 100644
index 0000000..7c30495
--- /dev/null
+++ b/docs/data/download_history.json
@@ -0,0 +1,30 @@
+[
+ {
+ "timestamp": "2024-10-27T00:00:00+00:00",
+ "total_downloads": 0
+ },
+ {
+ "timestamp": "2025-12-04T13:25:33.785415+00:00",
+ "total_downloads": 906514
+ },
+ {
+ "timestamp": "2025-12-04T13:26:09.117076+00:00",
+ "total_downloads": 906524
+ },
+ {
+ "timestamp": "2025-12-04T13:46:48.639327+00:00",
+ "total_downloads": 906741
+ },
+ {
+ "timestamp": "2025-12-04T13:53:02.674280+00:00",
+ "total_downloads": 906828
+ },
+ {
+ "timestamp": "2025-12-04T13:53:35.050423+00:00",
+ "total_downloads": 906834
+ },
+ {
+ "timestamp": "2025-12-04T13:56:13.655744+00:00",
+ "total_downloads": 906837
+ }
+]
\ No newline at end of file
diff --git a/update_download_stats.py b/update_download_stats.py
new file mode 100644
index 0000000..c48e47f
--- /dev/null
+++ b/update_download_stats.py
@@ -0,0 +1,193 @@
+#!/usr/bin/env python3
+"""
+Fetch GitHub release download statistics and generate a graph.
+
+This script fetches download counts from GitHub API, stores historical data,
+and generates a graph showing download trends over time.
+"""
+
+import json
+from datetime import datetime, timezone
+from pathlib import Path
+
+import matplotlib.pyplot as plt
+import requests
+
+
+def fetch_download_stats(owner: str, repo: str) -> dict:
+ """
+ Fetch download statistics from GitHub API.
+
+ Args:
+ owner: Repository owner
+ repo: Repository name
+
+ Returns:
+ dict: Dictionary containing total downloads and timestamp
+ """
+ url = f"https://api.github.com/repos/{owner}/{repo}/releases"
+ headers = {}
+
+ # Fetch all releases with pagination
+ all_releases = []
+ page = 1
+ per_page = 100 # Maximum per page allowed by GitHub API
+
+ while True:
+ params = {"page": page, "per_page": per_page}
+ response = requests.get(url, headers=headers, params=params)
+ response.raise_for_status()
+
+ releases = response.json()
+ if not releases:
+ break
+
+ all_releases.extend(releases)
+ page += 1
+
+ # Check if there are more pages
+ if len(releases) < per_page:
+ break
+
+ print(f"Fetched {len(all_releases)} releases")
+
+ total_downloads = 0
+ release_data = []
+
+ for release in all_releases:
+ release_downloads = 0
+ for asset in release.get("assets", []):
+ release_downloads += asset.get("download_count", 0)
+
+ total_downloads += release_downloads
+ release_data.append(
+ {
+ "tag": release["tag_name"],
+ "name": release["name"],
+ "downloads": release_downloads,
+ "created_at": release["created_at"],
+ }
+ )
+
+ return {
+ "total_downloads": total_downloads,
+ "releases": release_data,
+ }
+
+
+def load_history(filepath: Path) -> list:
+ """
+ Load historical download statistics from JSON file.
+
+ Args:
+ filepath: Path to the history JSON file
+
+ Returns:
+ list: List of historical data points
+ """
+ if not filepath.exists():
+ return []
+
+ with open(filepath, "r") as f:
+ return json.load(f)
+
+
+def save_history(filepath: Path, history: list) -> None:
+ """
+ Save historical download statistics to JSON file.
+
+ Args:
+ filepath: Path to the history JSON file
+ history: List of historical data points
+ """
+ filepath.parent.mkdir(parents=True, exist_ok=True)
+ with open(filepath, "w") as f:
+ json.dump(history, f, indent=2)
+
+
+def generate_graph(history: list, output_path: Path, label: str = "") -> None:
+ """
+ Generate a download statistics graph in Star History (XKCD) style.
+ """
+ if len(history) < 2:
+ print("Not enough data to generate a graph (need at least 2 data points)")
+ return
+
+ dates = [datetime.fromisoformat(entry["timestamp"]) for entry in history]
+ downloads = [entry["total_downloads"] for entry in history]
+
+ # --- XKCD Style Context ---
+ # これにより手書き風のエフェクト(歪んだ線、手書きフォント)が適用されます
+ with plt.xkcd():
+ fig, ax = plt.subplots(figsize=(8, 6))
+
+ # Star History風の色(オレンジ/赤系)
+ line_color = "#f05133"
+
+ # プロット
+ ax.plot(
+ dates,
+ downloads,
+ color=line_color,
+ linewidth=3,
+ label=label if label else "Downloads",
+ )
+
+ if label:
+ legend = ax.legend(loc="upper left", frameon=True, fontsize=10)
+ legend.get_frame().set_edgecolor("black")
+ legend.get_frame().set_linewidth(1.5)
+
+ ax.spines["right"].set_color("none")
+ ax.spines["top"].set_color("none")
+
+ ax.spines["bottom"].set_linewidth(1.5)
+ ax.spines["left"].set_linewidth(1.5)
+
+ plt.title("Download History", fontsize=16, y=1.05)
+ plt.xlabel("Date", fontsize=12)
+ plt.ylabel("Total Downloads", fontsize=12)
+
+ ax.set_ylim(bottom=0)
+
+ ax.yaxis.set_major_formatter(plt.FuncFormatter(lambda x, p: f"{int(x):,}"))
+
+ fig.autofmt_xdate(rotation=0, ha="center")
+
+ plt.tight_layout()
+
+ output_path.parent.mkdir(parents=True, exist_ok=True)
+ plt.savefig(output_path, dpi=150, bbox_inches="tight", facecolor="white")
+ print(f"Graph saved to {output_path}")
+
+
+def main():
+ """Main function to update download statistics and generate graph."""
+ owner = "mjun0812"
+ repo = "flash-attention-prebuild-wheels"
+ history_file = Path("docs/data/download_history.json")
+ graph_output = Path("docs/data/download_graph.png")
+
+ # Fetch current stats
+ print("Fetching download statistics from GitHub API...")
+ current_stats = fetch_download_stats(owner, repo)
+ print(f"Total downloads: {current_stats['total_downloads']}")
+
+ # Load and update history
+ history = load_history(history_file)
+ history.append(
+ {
+ "timestamp": datetime.now(timezone.utc).isoformat(),
+ "total_downloads": current_stats["total_downloads"],
+ }
+ )
+
+ # Save updated history
+ save_history(history_file, history)
+ print(f"History saved to {history_file}")
+
+ generate_graph(history, graph_output, f"{owner}/{repo}")
+
+
+if __name__ == "__main__":
+ main()